﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.Hosting;
using System.Web.UI.WebControls;
using iTextSharp.text;
using iTextSharp.text.pdf;
using Microsoft.SqlServer.Server;
using Nop.Core;
using Nop.Core.Domain;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain.Localization;
using Nop.Core.Domain.Logistics;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Payments;
using Nop.Core.Domain.Shipping;
using Nop.Core.Domain.Tax;
using Nop.Core.Html;
using Nop.Services.Catalog;
using Nop.Services.Customers;
using Nop.Services.Directory;
using Nop.Services.Helpers;
using Nop.Services.Localization;
using Nop.Services.Logistics;
using Nop.Services.Media;
using Nop.Services.Orders;
using Nop.Services.Payments;
using Nop.Services.Stores;
using Nop.Services.Tax;
using OfficeOpenXml.Style;
using Image = iTextSharp.text.Image;

namespace Nop.Services.Common
{
    /// <summary>
    /// PDF service
    /// </summary>
    public partial class PdfService : IPdfService
    {
        #region Constants
        private const float PIXELS_PER_INCH = 72f;

        private const float WAYBILL_PAGE_WIDTH_IN_INCHES = 4f;
        private const float WAYBILL_PAGE_HEIGHT_IN_INCHES = 6f;
        private const string WAYBILL_LINEAR_MEASURE_SYSTEMNAME = "centimetres";
        #endregion

        #region Fields

        private readonly ILocalizationService _localizationService;
        private readonly IOrderService _orderService;
        private readonly IPaymentService _paymentService;
        private readonly IDateTimeHelper _dateTimeHelper;
        private readonly IPriceFormatter _priceFormatter;
        private readonly ICurrencyService _currencyService;
        private readonly IMeasureService _measureService;
        private readonly IPictureService _pictureService;
        private readonly IProductService _productService;
        private readonly IAddressService _addressService;
        private readonly ICustomerService _customerService;
        private readonly ILogisticsService _logisticsService;
        private readonly ITaxService _taxSerivce;
        private readonly IWebHelper _webHelper;
        private readonly InvoiceSettings _invoiceSettings;

        private readonly CatalogSettings _catalogSettings;
        private readonly CurrencySettings _currencySettings;
        private readonly MeasureSettings _measureSettings;
        private readonly PdfSettings _pdfSettings;
        private readonly TaxSettings _taxSettings;
        private readonly StoreInformationSettings _storeInformationSettings;
        private readonly AddressSettings _addressSettings;
        private readonly QrCodeSettings _qrCodeSettings;
        private readonly LogisticsInformationSettings _logisticsInformationSettings;
        private readonly IStoreService _storeService;
        private readonly IBranchService _branchService;
        private readonly IWorkContext _workContext;
        #endregion

        #region Ctor

        public PdfService(ILocalizationService localizationService, IOrderService orderService,
            IPaymentService paymentService,
            IDateTimeHelper dateTimeHelper, IPriceFormatter priceFormatter,
            ICurrencyService currencyService, IMeasureService measureService,
            IPictureService pictureService, IProductService productService,
            IAddressService addressService, ICustomerService customerService,
            ILogisticsService logisticsService, ITaxService taxService,
            IWebHelper webHelper,
            InvoiceSettings invoiceSettings,
            CatalogSettings catalogSettings, CurrencySettings currencySettings,
            MeasureSettings measureSettings, PdfSettings pdfSettings, TaxSettings taxSettings,
            StoreInformationSettings storeInformationSettings, AddressSettings addressSettings,
            QrCodeSettings qrCodeSettings, LogisticsInformationSettings logisticsInformationSettings,
            IStoreService storeService, IBranchService branchService, IWorkContext workContext)
        {
            this._localizationService = localizationService;
            this._orderService = orderService;
            this._paymentService = paymentService;
            this._dateTimeHelper = dateTimeHelper;
            this._priceFormatter = priceFormatter;
            this._currencyService = currencyService;
            this._measureService = measureService;
            this._pictureService = pictureService;
            this._productService = productService;
            this._addressService = addressService;
            this._customerService = customerService;
            this._logisticsService = logisticsService;
            this._taxSerivce = taxService;
            this._webHelper = webHelper;
            this._invoiceSettings = invoiceSettings;
            this._currencySettings = currencySettings;
            this._catalogSettings = catalogSettings;
            this._measureSettings = measureSettings;
            this._pdfSettings = pdfSettings;
            this._taxSettings = taxSettings;
            this._storeInformationSettings = storeInformationSettings;
            this._addressSettings = addressSettings;
            this._qrCodeSettings = qrCodeSettings;
            this._logisticsInformationSettings = logisticsInformationSettings;
            this._storeService = storeService;
            this._branchService = branchService;
            this._workContext = workContext;
        }

        #endregion

        #region Utilities

        protected virtual Font GetFont()
        {
            //nopCommerce supports unicode characters
            //nopCommerce uses Free Serif font by default (~/App_Data/Pdf/FreeSerif.ttf file)
            //It was downloaded from http://savannah.gnu.org/projects/freefont
            string fontPath = Path.Combine(_webHelper.MapPath("~/App_Data/Pdf/"), _pdfSettings.FontFileName);
            var baseFont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            var font = new Font(baseFont, 10, Font.NORMAL);
            return font;
        }

        protected virtual Font GetRobotoFont()
        {
            string fontPath = Path.Combine(_webHelper.MapPath("~/App_Data/Pdf/"), "Roboto-Regular.ttf");
            var baseFont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            var font = new Font(baseFont, 10, Font.NORMAL);
            return font;
        }

        protected virtual Font GetRobotoBoldFont()
        {
            string fontPath = Path.Combine(_webHelper.MapPath("~/App_Data/Pdf/"), "Roboto-Bold.ttf");
            var baseFont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            var font = new Font(baseFont, 10, Font.NORMAL);
            return font;
        }

        /// <summary>
        /// Populate the content of a Logistics Waybill in a PDF.
        /// </summary>
        /// <param name="doc">Document object that is already opened and associated to a file stream</param>
        /// <param name="package">Logistics package</param>
        /// <param name="trackingUrl">Tracking Url for this package</param>
        /// <param name="lang">Language</param>
        /// <param name="isisReturnRequestLogisticOrder">is add return to shipping lable</param>
        private void populateWaybillAsPdf(Document doc, LogisticsPackage package, string trackingUrl, Language lang, bool isisReturnRequestLogisticOrder = false)
        {
            if (doc == null)
                throw new ArgumentNullException("doc");

            if (package == null)
                throw new ArgumentNullException("package");

            if (String.IsNullOrEmpty(trackingUrl))
                throw new ArgumentNullException("trackingUrl");

            if (lang == null)
                throw new ArgumentNullException("lang");

            if (!doc.IsOpen())
                throw new ArgumentException("document object provided must be opened caller!");

            var pickUpLoc = package.PickUpLocation;
            var deliveryLoc = package.DeliveryLocation;

            //fonts
            var titleFont = GetFont();
            titleFont.SetStyle(Font.BOLD);
            titleFont.Color = BaseColor.BLACK;
            titleFont.Size = 18f;

            var sectionTitleFont = GetFont();
            sectionTitleFont.SetStyle(Font.BOLD + Font.UNDERLINE);
            sectionTitleFont.Color = BaseColor.BLACK;
            sectionTitleFont.Size = 12f;

            var qrCodeBoundaryTextStyle = GetFont();
            qrCodeBoundaryTextStyle.SetStyle(Font.BOLD);
            qrCodeBoundaryTextStyle.Color = BaseColor.WHITE;
            qrCodeBoundaryTextStyle.Size = 12f;

            var orderInfoFont = GetFont();
            orderInfoFont.Size = 8f;

            var font = GetFont();

            // Waybill title at the top section
            var titleTable = new PdfPTable(new float[] { 8.5f, 83f, 8.5f });
            titleTable.WidthPercentage = 100f;
            var titleCell = new PdfPCell();
            titleCell.Border = Rectangle.NO_BORDER;
            titleCell.HorizontalAlignment = Element.ALIGN_CENTER;
            titleCell.VerticalAlignment = Element.ALIGN_MIDDLE;

            titleTable.AddCell(titleCell);

            titleCell.Phrase = new Phrase("SpotsHUB EXPRESS", titleFont);
            titleTable.AddCell(titleCell);

            bool isNightDelivery = package.Shipment.Attributes.HasValue && ((package.Shipment.Attributes.Value & (int)(AddtionalAttributes.NightDeliver)) != 0);
            if (isNightDelivery)
            {
                titleCell.Phrase = new Phrase("N", qrCodeBoundaryTextStyle);
                titleCell.HorizontalAlignment = Element.ALIGN_CENTER;
                titleCell.VerticalAlignment = Element.ALIGN_CENTER;
                var bc = titleCell.BackgroundColor;
                titleCell.BackgroundColor = BaseColor.BLACK;
                titleTable.AddCell(titleCell);
                titleCell.BackgroundColor = bc;
            }
            else
            {
                titleCell.Phrase = null;
                titleTable.AddCell(titleCell);
            }

            titleCell.Phrase = new Phrase("---------------------------------", titleFont);
            titleCell.Colspan = 3;
            titleTable.AddCell(titleCell);

            doc.Add(titleTable);


            // Delivery Location and QR Code
            var sb = new System.Text.StringBuilder();
            sb.Append(String.Format("{0}\n", deliveryLoc.Address.Company));
            sb.Append(String.Format("{0} {1}\n", deliveryLoc.Address.FirstName,
                                                 deliveryLoc.Address.LastName));
            sb.Append(String.Format("{0}\n", deliveryLoc.Address.FormattedAddress(true)));
            sb.Append(String.Format("{0}\n", deliveryLoc.Address.CellPhoneNumber));
            sb.Append(String.Format("{0}\n", deliveryLoc.Address.PhoneNumber));


            var deliveryInfo = sb.ToString();

            var table = new PdfPTable(3);
            table.HorizontalAlignment = Element.ALIGN_LEFT;
            table.WidthPercentage = 100f;
            table.SetWidths(new int[] { 49, 2, 49 });

            var nestedTable = new PdfPTable(1);

            var deliveryTitle = "SHIP TO";
            if (deliveryLoc != null && deliveryLoc.Address != null && deliveryLoc.Address.Type.HasValue && deliveryLoc.Address.Type.Value != AddressType.Unknown)
            {
                deliveryTitle += String.Format(" ({0})", deliveryLoc.Address.Type.Value.GetLocalizedEnum(_localizationService, lang.Id));
            }
            var cell = new PdfPCell(new Phrase(deliveryTitle, sectionTitleFont));
            cell.Border = Rectangle.NO_BORDER;
            cell.HorizontalAlignment = Element.ALIGN_LEFT;
            cell.SetLeading(0f, 1.2f);
            table.AddCell(cell);

            cell.Phrase = new Phrase(null, font);
            table.AddCell(cell);

            var qrCodeTextCell = new PdfPCell();
            qrCodeTextCell.BackgroundColor = BaseColor.BLACK;
            qrCodeTextCell.Border = Rectangle.NO_BORDER;
            qrCodeTextCell.HorizontalAlignment = Element.ALIGN_CENTER;
            qrCodeTextCell.VerticalAlignment = Element.ALIGN_MIDDLE;
            // qrCodeTextCell.SetLeading(0f, 1.0f);

            qrCodeTextCell.Phrase = new Phrase(package.Shipment.TrackingNumber, qrCodeBoundaryTextStyle);
            table.AddCell(qrCodeTextCell);

            cell.Phrase = new Phrase(deliveryInfo, font);
            nestedTable.AddCell(cell);

            var cb = new System.Text.StringBuilder();

            // Comment
            if (!String.IsNullOrEmpty(package.Shipment.Comment))
            {
                cb.AppendFormat("{0}\n", package.Shipment.Comment);
                var commentString = cb.ToString();
                var commentCell = new PdfPCell();
                commentCell.Phrase = new Phrase(commentString, font);
                commentCell.Border = Rectangle.TOP_BORDER | Rectangle.BOTTOM_BORDER | Rectangle.LEFT_BORDER | Rectangle.RIGHT_BORDER;
                commentCell.BorderColor = new BaseColor(0, 0, 0);
                commentCell.Padding = 4f;
                nestedTable.AddCell(commentCell);
            }

            var nestedCell = new PdfPCell(nestedTable);
            nestedCell.Border = Rectangle.NO_BORDER;
            table.AddCell(nestedCell);

            cell.Phrase = new Phrase(null, font);
            table.AddCell(cell);

            nestedTable = new PdfPTable(1);

            Image trackingQrCodeImg = null;
            if (_qrCodeSettings.Enabled)
            {
                trackingQrCodeImg = new BarcodeQRCode(trackingUrl, _qrCodeSettings.PackagingSlipWidth, _qrCodeSettings.PackagingSlipHeight, null).GetImage();
                var cellQr = new PdfPCell(trackingQrCodeImg);
                cellQr.Border = Rectangle.NO_BORDER;
                cellQr.BorderWidthBottom = 0f;
                cellQr.BorderWidthTop = 0f;
                cellQr.HorizontalAlignment = Element.ALIGN_CENTER;
                cellQr.VerticalAlignment = Element.ALIGN_MIDDLE;
                cellQr.PaddingTop = 0f;
                cellQr.PaddingBottom = 0f;
                nestedTable.AddCell(cellQr);
            }

            if (_qrCodeSettings.BarCodeEnabled)
            {
                var barCode = new Barcode128()
                {
                    Code = package.Shipment.TrackingNumber
                };

                var barCodeImg = Image.GetInstance(barCode.CreateDrawingImage(System.Drawing.Color.Black, System.Drawing.Color.White), BaseColor.BLACK);
                var cellBar = new PdfPCell(barCodeImg);
                cellBar.Border = Rectangle.NO_BORDER;
                cellBar.BorderWidthBottom = 0f;
                cellBar.BorderWidthTop = 0f;
                cellBar.HorizontalAlignment = Element.ALIGN_CENTER;
                cellBar.VerticalAlignment = Element.ALIGN_MIDDLE;
                cellBar.PaddingTop = 0f;
                cellBar.PaddingBottom = 0f;
                nestedTable.AddCell(cellBar);
            }

            // TODO: Should be implemented with mapping in a separate class file.
            if (pickUpLoc.Package.Shipment.Attributes.HasValue && pickUpLoc.Package.Shipment.Attributes.Value != (int)AddtionalAttributes.None)
            {
                string packageAttributeStr;
                var att = (AddtionalAttributes)pickUpLoc.Package.Shipment.Attributes.Value;
                packageAttributeStr = att.GetLocalizedEnum(_localizationService, lang.Id);

                qrCodeBoundaryTextStyle.Color = BaseColor.WHITE;
                qrCodeTextCell.Phrase = new Phrase(packageAttributeStr, qrCodeBoundaryTextStyle);
                qrCodeTextCell.HorizontalAlignment = Element.ALIGN_CENTER;
                var t = new PdfPTable(1);
                t.WidthPercentage = 100f;
                t.AddCell(qrCodeTextCell);
                var c = new PdfPCell();
                c.Border = Rectangle.NO_BORDER;
                c.VerticalAlignment = Element.ALIGN_BOTTOM;
                c.AddElement(t);
                nestedTable.AddCell(c);
            }

            nestedCell = new PdfPCell(nestedTable);
            nestedCell.Border = Rectangle.NO_BORDER;
            table.AddCell(nestedCell);

            doc.Add(table);

            // Order Info Information
            sb.Clear();


            string orderByInfo = null;
            if (package.Shipment != null && package.Shipment.Order != null && !String.IsNullOrWhiteSpace(package.Shipment.Order.OrderByInfo))
            {
                orderByInfo = package.Shipment.Order.OrderByInfo;
            }
            else if (package.ApplicatorId.HasValue)
            {
                // Enable customized order information
                var customer = _customerService.GetCustomerById(package.ApplicatorId.Value);
                if (customer != null)
                {
                    orderByInfo = customer.GetCompanyNameOrFullName();
                }
            }

            if (!String.IsNullOrWhiteSpace(orderByInfo))
            {
                sb.AppendLine("Order By:");
                sb.AppendLine(orderByInfo);
            }

            var orderInfoPart1 = sb.ToString();

            sb.Clear();
            sb.Append(String.Format("Tracking #: {0}\n",
                        pickUpLoc.Package.Shipment.TrackingNumber));

            if (pickUpLoc.Package.Shipment.SpotshubPackageSize >= 0)
            {
                if (pickUpLoc.Package.Shipment.Order.BoundOrderId == null || pickUpLoc.Package.Shipment.Order.OrderKindId == 20)
                {
                    switch (pickUpLoc.Package.Shipment.SpotshubPackageSize)
                    {
                        case 0:
                            sb.AppendLine(_localizationService.GetResource("Logistics.Order.Package.Size.Letter", lang.Id));
                            break;
                        case 1:
                            sb.AppendLine(_localizationService.GetResource("Logistics.Order.Package.Size.Small", lang.Id));
                            break;
                        case 2:
                            sb.AppendLine(_localizationService.GetResource("Logistics.Order.Package.Size.Medium", lang.Id));
                            break;
                        case 3:
                            sb.AppendLine(_localizationService.GetResource("Logistics.Order.Package.Size.Large", lang.Id));
                            break;
                        case 4:
                            sb.AppendLine(_localizationService.GetResource("Logistics.Order.Package.Size.ExtraLarge", lang.Id));
                            break;
                    }
                }
                else
                {
                    sb.AppendLine(_localizationService.GetResource("Logistics.Order.Package.Size.E-commerce", lang.Id));
                }
                //if (pickUpLoc.Package.Shipment.SpotshubPackageSize == 2)
                //{
                //    sb.AppendLine(_localizationService.GetResource("Logistics.Order.Package.CompactSize", lang.Id));
                //}
                //else if (pickUpLoc.Package.Shipment.SpotshubPackageSize == 3)
                //{
                //    sb.AppendLine(_localizationService.GetResource("Logistics.Order.Package.FullSize", lang.Id));
                //}
                //else
                //{
                //    sb.AppendLine(_localizationService.GetResource("Logistics.StandardPackage", lang.Id));
                //}
            }
            else
            {
                var linearMeasureDim = _measureService.GetMeasureDimensionById(_measureSettings.BaseDimensionId);
                sb.Append(String.Format("Dimension ({0}): ", linearMeasureDim.Name));
                if (pickUpLoc.Package.Shipment.Length.HasValue &&
                    pickUpLoc.Package.Shipment.Width.HasValue &&
                    pickUpLoc.Package.Shipment.Height.HasValue)
                {
                    sb.Append(String.Format("{0:F2} x {1:F2} x {2:F2}\n",
                                            pickUpLoc.Package.Shipment.Length.Value,
                                            pickUpLoc.Package.Shipment.Width.Value,
                                            pickUpLoc.Package.Shipment.Height.Value));
                }

                var weightMeasure = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId);
                sb.Append(String.Format("Weight ({0}): ", weightMeasure.Name));
                if (pickUpLoc.Package.Shipment.TotalWeight.HasValue)
                {
                    sb.Append(String.Format("{0:F2} \n",
                               pickUpLoc.Package.Shipment.TotalWeight.Value
                               ));
                }
            }
            sb.Append("\n");

            var orderInfoPart2 = sb.ToString();

            var table2 = new PdfPTable(2);
            table2.HorizontalAlignment = Element.ALIGN_LEFT;
            table2.WidthPercentage = 100f;
            table2.SetWidths(new int[] { 50, 50 });

            var cell2Title = new PdfPCell(new Phrase("Order Details", sectionTitleFont));
            cell2Title.Border = Rectangle.LEFT_BORDER | Rectangle.RIGHT_BORDER | Rectangle.TOP_BORDER;
            cell2Title.HorizontalAlignment = Element.ALIGN_LEFT;
            cell2Title.Colspan = 2;
            cell2Title.SetLeading(2f, 1.2f);
            table2.AddCell(cell2Title);

            var cell2 = new PdfPCell(new Phrase(orderInfoPart1, orderInfoFont));
            cell2.Border = Rectangle.LEFT_BORDER | Rectangle.BOTTOM_BORDER;
            cell2.SetLeading(2f, 1.2f);
            table2.AddCell(cell2);

            cell2.Phrase = new Phrase(orderInfoPart2, orderInfoFont);
            cell2.Border = Rectangle.RIGHT_BORDER | Rectangle.BOTTOM_BORDER;
            cell2.HorizontalAlignment = Element.ALIGN_LEFT;
            cell2.SetLeading(2f, 1.2f);
            table2.AddCell(cell2);

            if (isisReturnRequestLogisticOrder)
            {
                cell2.Phrase = new Phrase("Return", sectionTitleFont);
                cell2.Border = Rectangle.NO_BORDER;
                cell2.HorizontalAlignment = Element.ALIGN_LEFT;
                cell2.SetLeading(2f, 1.2f);
                cell2.Colspan = 2;
                table2.AddCell(cell2);
            }

            var spacingFont = GetFont();
            spacingFont.Size = 2f;

            var spaceBeforeTable2 = new Paragraph(String.Format(""), spacingFont);
            spaceBeforeTable2.SpacingAfter = 2f;
            doc.Add(spaceBeforeTable2);

            doc.Add(table2);

            // Custom area content
            var customAreaFont = GetFont();
            customAreaFont.SetStyle(Font.BOLD);
            customAreaFont.Color = BaseColor.BLACK;
            customAreaFont.Size = 12f;

            var customAreaContent = new Paragraph("www.SpotsHUB.com", customAreaFont);
            customAreaContent.Alignment = Element.ALIGN_CENTER;
            customAreaContent.SpacingBefore = 20f;
            doc.Add(customAreaContent);
            customAreaFont.Size = 8f;
            var sloganLine1 = _localizationService.GetResource("Logistics.Waybill.Slogan", lang.Id);
            var sloganLine2 = _localizationService.GetResource("Logistics.Waybill.Slogan2", lang.Id);
            customAreaContent = new Paragraph();
            customAreaContent.Font = customAreaFont;
            customAreaContent.Leading = 12f;
            if (!String.IsNullOrEmpty(sloganLine2))
                sloganLine1 += "\n";
            customAreaContent.Add(sloganLine1);
            if (!String.IsNullOrEmpty(sloganLine2))
                customAreaContent.Add(sloganLine2);
            customAreaContent.Alignment = Element.ALIGN_CENTER;
            customAreaContent.SpacingBefore = 10f;
            doc.Add(customAreaContent);
        }

        /// <summary>
        /// Populate the content of an Express Invoice in a PDF.
        /// </summary>
        /// <param name="doc">Document object that is already opened and associated to a file stream</param>
        /// <param name="invoice">An invoice</param>
        /// <param name="lang">Language</param>
        /// <param name="useCustomerTimeZone">Use customer time zone or invoice</param>
        private void populateExpressInvoiceAsPdf(Document doc, Invoice invoice, Language lang, bool useCustomerTimeZone)
        {
            if (invoice.Customer == null)
            {
                throw new NopException("The invoice doesn't associate with a customer. ID {0}", invoice.Id);
            }

            TimeZoneInfo timeZoneInfo = null;
            if (useCustomerTimeZone)
            {
                timeZoneInfo = _dateTimeHelper.GetCustomerTimeZone(invoice.Customer);
            }
            else
            {
                timeZoneInfo = _dateTimeHelper.FindTimeZoneById(invoice.TimeZoneId);
            }
            if (timeZoneInfo == null)
            {
                throw new NopException("The invoice doesn't have time zone info. ID {0}", invoice.Id);
            }

            //fonts
            var titleFont = GetFont();
            titleFont.SetStyle(Font.BOLD);
            titleFont.Color = BaseColor.BLACK;
            var font = GetFont();
            font.Size = 7;
            var attributesFont = GetFont();
            attributesFont.SetStyle(Font.ITALIC);
            var descriptionFont = GetFont();
            descriptionFont.SetStyle(Font.ITALIC);
            descriptionFont.Size = 7;

            var emptyBorderlessCell = new PdfPCell(new Phrase(""));
            emptyBorderlessCell.Border = Rectangle.NO_BORDER;

            #region Header

            // Header table
            var headerTable = new PdfPTable(2);
            headerTable.WidthPercentage = 100f;
            headerTable.SetWidths(new[] { 50, 50 });

            #region Hearder Logo & Invoice Title Row

            //logo
            var imagePath = _webHelper.MapPath("~/content/images");
            var imageFile = "spotshub-textlogo-print.png";
            byte[] logoPicBinary;
            if (!File.Exists(Path.Combine(imagePath, imageFile)))
            {
                logoPicBinary = new byte[0];
            }
            else
            {
                logoPicBinary = File.ReadAllBytes(Path.Combine(imagePath, imageFile));
            }

            var logoExists = true;
            if (logoPicBinary == null || logoPicBinary.Length == 0)
                logoExists = false;

            //header
            //var headerTable = new PdfPTable(logoExists ? 2 : 1);
            //headerTable.WidthPercentage = 100f;
            //if (logoExists)
            //    headerTable.SetWidths(new[] { 50, 50 });

            //logo
            if (logoExists)
            {
                //var logoFilePath = _pictureService.GetPictureLocalPath(logoPicture, 0, false);
                var logoFilePath = Path.Combine(imagePath, imageFile);
                var logoImg = Image.GetInstance(logoFilePath);
                //logoImg.ScaleAbsoluteWidth(4f * PIXELS_PER_INCH);
                var cellLogo = new PdfPCell(logoImg);
                cellLogo.Border = Rectangle.NO_BORDER;
                cellLogo.HorizontalAlignment = Element.ALIGN_LEFT;
                cellLogo.PaddingTop = 0f;
                headerTable.AddCell(cellLogo);
            }
            else
            {
                headerTable.AddCell(new PdfPCell());
            }

            //invoice title
            var invoiceTitleWordFont = GetFont();
            invoiceTitleWordFont.Size = 16;
            invoiceTitleWordFont.SetStyle(Font.BOLD);
            var cell = new PdfPCell(new Paragraph("", invoiceTitleWordFont));
            cell.Border = Rectangle.NO_BORDER;
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;

            if (invoice.InvoiceStatus == InvoiceStatus.Paid ||
                invoice.InvoiceStatus == InvoiceStatus.PaidByCheck ||
                invoice.InvoiceStatus == InvoiceStatus.PaidByCreditCard)
            {
                imageFile = "paid-icon.jpg";
                var logoFilePath = Path.Combine(imagePath, imageFile);
                var logoImg = Image.GetInstance(logoFilePath);
                logoImg.ScalePercent(50.0f);
                var cellPaid = new PdfPCell(logoImg);
                cellPaid.Border = Rectangle.NO_BORDER;
                cellPaid.HorizontalAlignment = Element.ALIGN_RIGHT;
                cellPaid.PaddingTop = 0f;
                headerTable.AddCell(cellPaid);
            }
            else if (invoice.InvoiceStatus == InvoiceStatus.Refunded)
            {
                var sfont = GetFont();
                sfont.SetStyle(Font.BOLD);
                sfont.Color = BaseColor.RED;
                sfont.Size = 12;

                headerTable.AddCell(new PdfPCell()
                {
                    Border = Rectangle.NO_BORDER,
                    HorizontalAlignment = Element.ALIGN_RIGHT,
                    Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Refunded", lang.Id), sfont)
                });
            }
            else
            {
                headerTable.AddCell(new PdfPCell() { Border = Rectangle.NO_BORDER });
            }

            #endregion

            #region Addresses

            var headerAddressFont = GetFont();
            headerAddressFont.Size = 9;

            var addressTable = new PdfPTable(2);
            addressTable.WidthPercentage = 100f;
            addressTable.SetWidths(new[] { 50, 50 });

            // first line is: <empty column>  |   Billing to Customer
            addressTable.AddCell(emptyBorderlessCell);

            cell = new PdfPCell();
            cell.Border = Rectangle.NO_BORDER;
            cell.HorizontalAlignment = Element.ALIGN_LEFT;
            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.BillingInformation", lang.Id), titleFont);
            addressTable.AddCell(cell);

            //company address info
            var companyAddress = _addressService.GetAddressById(_pdfSettings.InvoiceCompanyAddressId);
            if (companyAddress != null)
            {
                cell = new PdfPCell();
                cell.Border = Rectangle.NO_BORDER;
                if (_addressSettings.StreetAddressEnabled)
                    cell.AddElement(new Paragraph(companyAddress.Address1, headerAddressFont));
                if (_addressSettings.CityEnabled || _addressSettings.StateProvinceEnabled || _addressSettings.ZipPostalCodeEnabled)
                    cell.AddElement(new Paragraph(String.Format("{0}, {1} {2}", companyAddress.City, companyAddress.StateProvince != null ? companyAddress.StateProvince.GetLocalized(x => x.Name, lang.Id) : "", companyAddress.ZipPostalCode), headerAddressFont));
                if (_addressSettings.PhoneEnabled)
                    cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Phone", lang.Id), companyAddress.PhoneNumber), headerAddressFont));
                if (!String.IsNullOrEmpty(companyAddress.Email))
                    cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Email", lang.Id), companyAddress.Email), headerAddressFont));
                if (_addressSettings.FaxEnabled && !String.IsNullOrEmpty(companyAddress.FaxNumber))
                    cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Fax", lang.Id), companyAddress.FaxNumber), headerAddressFont));
                if (!String.IsNullOrEmpty(_taxSettings.ExpressGstNumber))
                    cell.AddElement(new Paragraph(_taxSettings.ExpressGstNumber, headerAddressFont));
            }
            else
            {
                cell = new PdfPCell(new Phrase(" "));
                cell.Border = Rectangle.NO_BORDER;
            }

            addressTable.AddCell(cell);

            //billing info
            cell = new PdfPCell();
            cell.Border = Rectangle.NO_BORDER;

            if (_addressSettings.CompanyEnabled && !String.IsNullOrEmpty(invoice.Customer.BillingAddress.Company))
            {
                cell.AddElement(new Paragraph(invoice.Customer.BillingAddress.Company, headerAddressFont));
            }
            else
            {
                // only display first + last name if company name is empty
                cell.AddElement(new Paragraph(String.Format(invoice.Customer.GetFullName()), headerAddressFont));
            }

            string streetAddress = "";
            if (_addressSettings.StreetAddressEnabled && _addressSettings.StreetAddress2Enabled && !String.IsNullOrEmpty(invoice.Customer.BillingAddress.Address2))
            {
                streetAddress = String.Format("{0}-{1}", invoice.Customer.BillingAddress.Address2, invoice.Customer.BillingAddress.Address1);
            }
            else if (_addressSettings.StreetAddressEnabled)
            {
                streetAddress = invoice.Customer.BillingAddress.Address1;
            }

            if (!String.IsNullOrEmpty(streetAddress))
            {
                cell.AddElement(new Paragraph(streetAddress, headerAddressFont));
            }
            if (_addressSettings.CityEnabled || _addressSettings.StateProvinceEnabled || _addressSettings.ZipPostalCodeEnabled)
                cell.AddElement(new Paragraph(String.Format("{0}, {1} {2}", invoice.Customer.BillingAddress.City, invoice.Customer.BillingAddress.StateProvince != null ? invoice.Customer.BillingAddress.StateProvince.GetLocalized(x => x.Name, lang.Id) : "", invoice.Customer.BillingAddress.ZipPostalCode), headerAddressFont));

            if (_addressSettings.CellPhoneEnabled && !String.IsNullOrEmpty(invoice.Customer.BillingAddress.CellPhoneNumber))
                cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.CellPhone", lang.Id), invoice.Customer.BillingAddress.CellPhoneNumber), headerAddressFont));
            if (_addressSettings.PhoneEnabled && !String.IsNullOrEmpty(invoice.Customer.BillingAddress.PhoneNumber))
                cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Phone", lang.Id), invoice.Customer.BillingAddress.PhoneNumber), headerAddressFont));
            if (_addressSettings.FaxEnabled && !String.IsNullOrEmpty(invoice.Customer.BillingAddress.FaxNumber))
                cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Fax", lang.Id), invoice.Customer.BillingAddress.FaxNumber), headerAddressFont));
            if (!String.IsNullOrEmpty(invoice.Customer.BillingAddress.Email))
                cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Email", lang.Id), invoice.Customer.BillingAddress.Email), headerAddressFont));

            addressTable.AddCell(cell);

            var addressTableCell = new PdfPCell(addressTable);
            addressTableCell.Border = Rectangle.NO_BORDER;
            headerTable.AddCell(addressTableCell);
            doc.Add(new Paragraph(" "));

            #endregion

            #region Invoice info section on Header

            var invoiceInfoFont = GetFont();
            invoiceInfoFont.Size = headerAddressFont.Size;

            var invoiceHighlightFont = GetFont();
            invoiceHighlightFont.Size = headerAddressFont.Size;
            invoiceHighlightFont.SetStyle(Font.BOLD);

            var invoiceInfoTable = new PdfPTable(2);
            invoiceInfoTable.WidthPercentage = 100f;
            invoiceInfoTable.SetWidths(new[] { 70, 30 });

            cell = new PdfPCell();
            cell.Border = Rectangle.NO_BORDER;

            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.ClientNumber", lang.Id), invoiceInfoFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            invoiceInfoTable.AddCell(cell);

            cell.Phrase = new Phrase(invoice.CustomerId.ToString(), invoiceInfoFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            invoiceInfoTable.AddCell(cell);

            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.InvoiceNumber", lang.Id), invoiceInfoFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            invoiceInfoTable.AddCell(cell);

            cell.Phrase = new Phrase(invoice.InvoiceNumber, invoiceInfoFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            invoiceInfoTable.AddCell(cell);

            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Date", lang.Id), invoiceInfoFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            invoiceInfoTable.AddCell(cell);

            cell.Phrase = new Phrase(TimeZoneInfo.ConvertTimeFromUtc(invoice.CreatedOnUtc, timeZoneInfo).ToString("MM/dd/yyyy"), invoiceInfoFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            invoiceInfoTable.AddCell(cell);

            if (!String.IsNullOrEmpty(invoice.Name))
            {
                var invoiceNameTokens = invoice.Name.Split(':');

                if (invoiceNameTokens.Length == 2)
                {
                    cell.Phrase = new Phrase(String.Format("{0}:", invoiceNameTokens[0].Trim()), invoiceInfoFont);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    invoiceInfoTable.AddCell(cell);

                    cell.Phrase = new Phrase(invoiceNameTokens[1].Trim(), invoiceInfoFont);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    invoiceInfoTable.AddCell(cell);
                }
                else if (invoiceNameTokens.Length == 1)
                {
                    var invoiceNameValueIdx = -1;
                    if (!String.IsNullOrWhiteSpace(_invoiceSettings.LogisticsPayPerUse))
                        invoiceNameValueIdx = invoice.Name.IndexOf(_invoiceSettings.LogisticsPayPerUse);

                    if (invoiceNameValueIdx >= 0)
                    {
                        var invoiceNameValuePart = invoice.Name.Substring(invoiceNameValueIdx + _invoiceSettings.LogisticsPayPerUse.Length).Trim();

                        cell.Phrase = new Phrase(String.Format("{0}:", _invoiceSettings.LogisticsPayPerUse.Trim()), invoiceInfoFont);
                        cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                        invoiceInfoTable.AddCell(cell);

                        cell.Phrase = new Phrase(invoiceNameValuePart, invoiceInfoFont);
                        cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                        invoiceInfoTable.AddCell(cell);
                    }
                    else
                    {
                        cell.Phrase = new Phrase(invoice.Name, invoiceInfoFont);
                        cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                        cell.Colspan = 2;
                        //cell.AddElement(new Paragraph(invoice.Name, invoiceInfoFont));
                        invoiceInfoTable.AddCell(cell);

                        cell = new PdfPCell();
                        cell.Border = Rectangle.NO_BORDER;
                    }
                }
            }
            else
            {
                invoiceInfoTable.AddCell(emptyBorderlessCell);
                invoiceInfoTable.AddCell(emptyBorderlessCell);
            }

            invoiceInfoTable.AddCell(emptyBorderlessCell);
            invoiceInfoTable.AddCell(emptyBorderlessCell);

            if (invoice.DueDate.HasValue)
            {
                cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Due", lang.Id), invoiceHighlightFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                invoiceInfoTable.AddCell(cell);

                cell.Phrase = new Phrase(invoice.DueDate.Value.ToString("MM/dd/yyyy"), invoiceHighlightFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                invoiceInfoTable.AddCell(cell);
            }

            var statusOfPaymentMethods = new InvoiceStatus[] { 
                InvoiceStatus.PaidByCheck, 
                InvoiceStatus.PaidByCreditCard };

            if (statusOfPaymentMethods.Contains(invoice.InvoiceStatus))
            {
                cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.PaymentMethods", lang.Id), invoiceInfoFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                invoiceInfoTable.AddCell(cell);

                cell.Phrase = new Phrase(_localizationService.GetResource(String.Format("Invoice.PaymentMethod.{0}", invoice.InvoiceStatus.ToString()), lang.Id), invoiceInfoFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                invoiceInfoTable.AddCell(cell);

                if (invoice.PaidDateUtc.HasValue)
                {
                    cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.PaymentTime", lang.Id), invoiceInfoFont);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    invoiceInfoTable.AddCell(cell);

                    cell.Phrase = new Phrase(_dateTimeHelper.ConvertToUserTime(invoice.PaidDateUtc.Value, DateTimeKind.Utc).ToString(), invoiceInfoFont);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    invoiceInfoTable.AddCell(cell);
                }
            }

            var invoiceInfoTableCell = new PdfPCell(invoiceInfoTable);
            invoiceInfoTableCell.Border = Rectangle.NO_BORDER;
            headerTable.AddCell(invoiceInfoTableCell);

            #endregion

            doc.Add(headerTable);

            doc.Add(new Paragraph(" "));

            #endregion

            decimal totalRefundedAmount = decimal.Zero;

            if (invoice.Orders != null && invoice.Orders.Count > 0)
            {
                var expressOrders = invoice.Orders.Where(o => o.OrderKind == OrderKind.Express);
                var commerceOrders = invoice.Orders.Where(o => o.OrderKind == OrderKind.Commerce);

                if (expressOrders != null && expressOrders.Count() > 0)
                {
                    //services
                    //doc.Add(new Paragraph(_localizationService.GetResource("PDFInvoice.Service(s)", lang.Id), titleFont));
                    //doc.Add(new Paragraph(" "));

                    #region Service headers

                    var servicesTable = new PdfPTable(11);
                    //var servicesTable = new PdfPTable(4);
                    servicesTable.WidthPercentage = 100f;
                    servicesTable.SetWidths(new[] { 5, 4, 7, 9, 9, 9, 14, 14, 11, 13, 5 }); // should add to 100
                    //servicesTable.SetWidths(new[] { 10, 10, 72, 8 }); // should add to 100
                    servicesTable.HeaderRows = 1; // repeat the first row (header) on every page.

                    //order by
                    cell = new PdfPCell(new Paragraph(_localizationService.GetResource("PDFInvoice.OrderBy", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    servicesTable.AddCell(cell);

                    //order
                    //cell = new PdfPCell(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Order#", lang.Id), order.Id), font));
                    cell = new PdfPCell(new Paragraph(_localizationService.GetResource("PDFInvoice.TableOrder#", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    servicesTable.AddCell(cell);

                    //tracking
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.Tracking#", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    servicesTable.AddCell(cell);

                    //order time
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.OrderTime", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    servicesTable.AddCell(cell);

                    //pickup time
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.PickupTime", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    servicesTable.AddCell(cell);

                    //deliver time
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.DeliveryTime", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    servicesTable.AddCell(cell);

                    //pickup from
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.PickUpFrom", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    servicesTable.AddCell(cell);

                    //deliver to
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.DeliverTo", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    servicesTable.AddCell(cell);

                    //reference
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.Reference", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    servicesTable.AddCell(cell);

                    //package measurement
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.PackageMeasurement", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    servicesTable.AddCell(cell);

                    //fee
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.Fee", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    servicesTable.AddCell(cell);

                    #endregion

                    //measures
                    var baseWeight = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId);
                    var baseWeightIn = baseWeight != null ? baseWeight.Name : "";
                    var baseDimension = _measureService.GetMeasureDimensionById(_measureSettings.BaseDimensionId);
                    var baseDimensionIn = baseDimension != null ? baseDimension.Name : "";

                    foreach (var order in expressOrders)
                    {
                        #region Service

                        bool firstShipment = true;
                        var orderProductVariants = order.OrderProductVariants.Where(opv => opv.ProductVariantId == _logisticsInformationSettings.SpecialServiceProductVarianId);
                        int itemCount = orderProductVariants.Count() + order.Shipments.Count();
                        //service name
                        string svcName = "";
                        if (orderProductVariants.Count() > 0)
                        {
                            var pv = orderProductVariants.FirstOrDefault().ProductVariant;
                            if (!String.IsNullOrEmpty(pv.GetLocalized(x => x.Name, lang.Id)))
                                svcName = string.Format("{0} ({1})", pv.Product.GetLocalized(x => x.Name, lang.Id), pv.GetLocalized(x => x.Name, lang.Id));
                            else
                                svcName = pv.Product.GetLocalized(x => x.Name, lang.Id);
                        }

                        totalRefundedAmount += order.RefundedAmount;

                        foreach (var shipment in order.Shipments)
                        {
                            var package = _logisticsService.GetPackageByShipmentId(shipment.Id);

                            if (firstShipment)
                            {
                                // Order By
                                var orderByInfo = String.IsNullOrWhiteSpace(order.OrderByInfo) ?
                                    order.Customer.GetCompanyNameOrFullName() : order.OrderByInfo;

                                cell = new PdfPCell(new Paragraph(orderByInfo, font));
                                cell.Rowspan = itemCount;
                                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                                servicesTable.AddCell(cell);

                                // Order #
                                // ideally, should not use if statement but rather embedded PdfPTable!
                                cell = new PdfPCell(new Phrase(order.Id.ToString(), font));
                                cell.Rowspan = itemCount;
                                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                                servicesTable.AddCell(cell);
                            }

                            // Tracking
                            cell = new PdfPCell(new Paragraph(shipment.TrackingNumber, font));
                            cell.HorizontalAlignment = Element.ALIGN_LEFT;
                            servicesTable.AddCell(cell);

                            // Order time
                            cell = new PdfPCell(new Paragraph(TimeZoneInfo.ConvertTimeFromUtc(order.CreatedOnUtc, timeZoneInfo).ToString("MM/dd/yyyy h:mm tt"), font));
                            cell.HorizontalAlignment = Element.ALIGN_CENTER;
                            servicesTable.AddCell(cell);

                            // Pick Up Time
                            var pickupTimeStr = shipment.ShippedDateUtc.HasValue ? TimeZoneInfo.ConvertTimeFromUtc(shipment.ShippedDateUtc.Value, timeZoneInfo).ToString("MM/dd/yyyy h:mm tt") : "--";
                            if (package.Status == ShippingStatus.FailedPickUp)
                            {
                                pickupTimeStr = package.Status.GetLocalizedEnum(_localizationService, lang.Id);
                            }

                            cell = new PdfPCell(new Paragraph(pickupTimeStr, font));
                            cell.HorizontalAlignment = Element.ALIGN_CENTER;
                            servicesTable.AddCell(cell);

                            // Delivery time
                            cell = new PdfPCell(new Paragraph(shipment.DeliveryDateUtc.HasValue ? TimeZoneInfo.ConvertTimeFromUtc(shipment.DeliveryDateUtc.Value, timeZoneInfo).ToString("MM/dd/yyyy h:mm tt") : "--", font));
                            cell.HorizontalAlignment = Element.ALIGN_CENTER;
                            servicesTable.AddCell(cell);

                            // Pick Up From
                            cell = new PdfPCell(new Paragraph(formatAddress(package.PickUpLocation.Address), font));
                            cell.HorizontalAlignment = Element.ALIGN_LEFT;
                            servicesTable.AddCell(cell);

                            // Deliver To
                            cell = new PdfPCell(new Paragraph(formatAddress(package.DeliveryLocation.Address), font));
                            cell.HorizontalAlignment = Element.ALIGN_LEFT;
                            servicesTable.AddCell(cell);

                            // Reference
                            cell = new PdfPCell(new Paragraph(shipment.Comment ?? "", font));
                            cell.HorizontalAlignment = Element.ALIGN_LEFT;
                            servicesTable.AddCell(cell);

                            // Package Measurement
                            cell = new PdfPCell();
                            cell.HorizontalAlignment = Element.ALIGN_LEFT;
                            var pkgMeasure = new StringBuilder();

                            //if (shipment.Length.HasValue && shipment.Width.HasValue && shipment.Height.HasValue)
                            //{
                            //    pkgMeasure.Append(shipment.Length.HasValue && shipment.Width.HasValue && shipment.Height.HasValue ?
                            //        string.Format("{1:###.##}{0} x {2:###.##}{0} x {3:###.##}{0}", baseDimensionIn,
                            //        MathEx.Round(shipment.Length.Value, 2),
                            //        MathEx.Round(shipment.Width.Value, 2),
                            //        MathEx.Round(shipment.Height.Value, 2)) : "");
                            //}
                            //else
                            //{
                            //    if (shipment.SpotshubPackageSize == 2)
                            //    {
                            //        pkgMeasure.AppendLine(_localizationService.GetResource("Logistics.Order.Package.CompactSize", lang.Id));
                            //    }
                            //    else if (shipment.SpotshubPackageSize == 3)
                            //    {
                            //        pkgMeasure.AppendLine(_localizationService.GetResource("Logistics.Order.Package.FullSize", lang.Id));
                            //    }
                            //    else
                            //    {
                            //        pkgMeasure.AppendLine(_localizationService.GetResource("Logistics.StandardPackage", lang.Id));
                            //    }
                            //}

                            switch (shipment.SpotshubPackageSize)
                            {
                                case 0:
                                    pkgMeasure.AppendLine(_localizationService.GetResource("Logistics.Order.Package.Size.Letter", lang.Id));
                                    break;
                                case 1:
                                    pkgMeasure.AppendLine(_localizationService.GetResource("Logistics.Order.Package.Size.Small", lang.Id));
                                    break;
                                case 2:
                                    pkgMeasure.AppendLine(_localizationService.GetResource("Logistics.Order.Package.Size.Medium", lang.Id));
                                    break;
                                case 3:
                                    pkgMeasure.AppendLine(_localizationService.GetResource("Logistics.Order.Package.Size.Large", lang.Id));
                                    break;
                                case 4:
                                    pkgMeasure.AppendLine(_localizationService.GetResource("Logistics.Order.Package.Size.ExtraLarge", lang.Id));
                                    break;
                            }

                            if (shipment.Attributes.HasValue && (AddtionalAttributes)shipment.Attributes.Value != AddtionalAttributes.None)
                            {
                                pkgMeasure.Append(",");
                                pkgMeasure.Append(((AddtionalAttributes)shipment.Attributes.Value).GetLocalizedEnum(_localizationService, lang.Id));

                                if (shipment.InsuranceValue.HasValue)
                                {
                                    pkgMeasure.Append(",");
                                    pkgMeasure.Append(String.Format(_localizationService.GetResource("Logistics.Order.InsuranceFormat"), shipment.InsuranceValue.Value));
                                }
                            }

                            cell.Phrase = new Phrase(pkgMeasure.ToString(), font);
                            servicesTable.AddCell(cell);

                            if (firstShipment)
                            {
                                // ideally, should not use if statement but rather embedded PdfPTable!

                                //fee                                
                                cell = new PdfPCell(new Paragraph(_priceFormatter.FormatPrice(order.OrderSubtotalExclTax), font));
                                cell.Rowspan = itemCount;
                                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                                servicesTable.AddCell(cell);
                            }

                            if (firstShipment)
                            {
                                firstShipment = false;
                            }
                        }

                        foreach (var opv in orderProductVariants)
                        {
                            cell = new PdfPCell();
                            cell.Colspan = 8;
                            cell.HorizontalAlignment = Element.ALIGN_LEFT;
                            var p = new Phrase(new Chunk(svcName + " ", font));
                            var attributesChunk = new Chunk(HtmlHelper.ConvertHtmlToPlainText(opv.AttributeDescription, true, true), descriptionFont);
                            p.Add(attributesChunk);
                            cell.AddElement(p);
                            servicesTable.AddCell(cell);
                        }
                        #endregion
                    }
                    doc.Add(servicesTable);
                }

                if (commerceOrders != null && commerceOrders.Count() > 0)
                {
                    //products
                    doc.Add(new Paragraph(_localizationService.GetResource("PDFInvoice.Product(s)", lang.Id), titleFont));
                    doc.Add(new Paragraph(" "));

                    foreach (var order in commerceOrders)
                    {
                        totalRefundedAmount += order.RefundedAmount;

                        #region Products

                        var orderProductVariants = _orderService.GetAllOrderProductVariants(order.Id, null, null, null, null, null, null);

                        var productsTable = new PdfPTable(_catalogSettings.ShowProductSku ? 5 : 4);
                        productsTable.WidthPercentage = 100f;
                        productsTable.SetWidths(_catalogSettings.ShowProductSku ? new[] { 40, 15, 15, 15, 15 } : new[] { 40, 20, 20, 20 });

                        //product name
                        cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductName", lang.Id), font));
                        cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                        cell.HorizontalAlignment = Element.ALIGN_CENTER;
                        productsTable.AddCell(cell);

                        //SKU
                        if (_catalogSettings.ShowProductSku)
                        {
                            cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.SKU", lang.Id), font));
                            cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                            cell.HorizontalAlignment = Element.ALIGN_CENTER;
                            productsTable.AddCell(cell);
                        }

                        //price
                        cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductPrice", lang.Id), font));
                        cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                        cell.HorizontalAlignment = Element.ALIGN_CENTER;
                        productsTable.AddCell(cell);

                        //qty
                        cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductQuantity", lang.Id), font));
                        cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                        cell.HorizontalAlignment = Element.ALIGN_CENTER;
                        productsTable.AddCell(cell);

                        //total
                        cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductTotal", lang.Id), font));
                        cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                        cell.HorizontalAlignment = Element.ALIGN_CENTER;
                        productsTable.AddCell(cell);

                        for (int i = 0; i < orderProductVariants.Count; i++)
                        {
                            var orderProductVariant = orderProductVariants[i];
                            var pv = orderProductVariant.ProductVariant;

                            //product name
                            string name = "";
                            if (!String.IsNullOrEmpty(pv.GetLocalized(x => x.Name, lang.Id)))
                                name = string.Format("{0} ({1})", pv.Product.GetLocalized(x => x.Name, lang.Id), pv.GetLocalized(x => x.Name, lang.Id));
                            else
                                name = pv.Product.GetLocalized(x => x.Name, lang.Id);
                            cell = new PdfPCell();
                            cell.AddElement(new Paragraph(name, font));
                            cell.HorizontalAlignment = Element.ALIGN_LEFT;
                            var attributesParagraph = new Paragraph(HtmlHelper.ConvertHtmlToPlainText(orderProductVariant.AttributeDescription, true, true), attributesFont);
                            cell.AddElement(attributesParagraph);
                            productsTable.AddCell(cell);

                            //SKU
                            if (_catalogSettings.ShowProductSku)
                            {
                                cell = new PdfPCell(new Phrase(pv.Sku ?? String.Empty, font));
                                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                                productsTable.AddCell(cell);
                            }

                            //price
                            string unitPrice = string.Empty;
                            switch (order.CustomerTaxDisplayType)
                            {
                                case TaxDisplayType.ExcludingTax:
                                    {
                                        var opvUnitPriceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderProductVariant.UnitPriceExclTax, order.CurrencyRate);
                                        unitPrice = _priceFormatter.FormatPrice(opvUnitPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                                    }
                                    break;
                                case TaxDisplayType.IncludingTax:
                                    {
                                        var opvUnitPriceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderProductVariant.UnitPriceInclTax, order.CurrencyRate);
                                        unitPrice = _priceFormatter.FormatPrice(opvUnitPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);
                                    }
                                    break;
                            }
                            cell = new PdfPCell(new Phrase(unitPrice, font));
                            cell.HorizontalAlignment = Element.ALIGN_LEFT;
                            productsTable.AddCell(cell);

                            //qty
                            cell = new PdfPCell(new Phrase(orderProductVariant.Quantity.ToString(), font));
                            cell.HorizontalAlignment = Element.ALIGN_LEFT;
                            productsTable.AddCell(cell);

                            //total
                            string subTotal = string.Empty;
                            switch (order.CustomerTaxDisplayType)
                            {
                                case TaxDisplayType.ExcludingTax:
                                    {
                                        var opvPriceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderProductVariant.PriceExclTax, order.CurrencyRate);
                                        subTotal = _priceFormatter.FormatPrice(opvPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                                    }
                                    break;
                                case TaxDisplayType.IncludingTax:
                                    {
                                        var opvPriceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderProductVariant.PriceInclTax, order.CurrencyRate);
                                        subTotal = _priceFormatter.FormatPrice(opvPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);
                                    }
                                    break;
                            }
                            cell = new PdfPCell(new Phrase(subTotal, font));
                            cell.HorizontalAlignment = Element.ALIGN_LEFT;
                            productsTable.AddCell(cell);
                        }
                        doc.Add(productsTable);


                        #endregion

                        #region Checkout attributes

                        if (!String.IsNullOrEmpty(order.CheckoutAttributeDescription))
                        {
                            doc.Add(new Paragraph(" "));
                            string attributes = HtmlHelper.ConvertHtmlToPlainText(order.CheckoutAttributeDescription, true, true);
                            var pCheckoutAttributes = new Paragraph(attributes, font);
                            pCheckoutAttributes.Alignment = Element.ALIGN_RIGHT;
                            doc.Add(pCheckoutAttributes);
                            doc.Add(new Paragraph(" "));
                        }

                        #endregion

                        #region Totals

                        //subtotal
                        doc.Add(new Paragraph(" "));
                        switch (order.CustomerTaxDisplayType)
                        {
                            case TaxDisplayType.ExcludingTax:
                                {
                                    var orderSubtotalExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalExclTax, order.CurrencyRate);
                                    string orderSubtotalExclTaxStr = _priceFormatter.FormatPrice(orderSubtotalExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);

                                    var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Sub-Total", lang.Id), orderSubtotalExclTaxStr), font);
                                    p.Alignment = Element.ALIGN_RIGHT;
                                    doc.Add(p);
                                }
                                break;
                            case TaxDisplayType.IncludingTax:
                                {
                                    var orderSubtotalInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalInclTax, order.CurrencyRate);
                                    string orderSubtotalInclTaxStr = _priceFormatter.FormatPrice(orderSubtotalInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);

                                    var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Sub-Total", lang.Id), orderSubtotalInclTaxStr), font);
                                    p.Alignment = Element.ALIGN_RIGHT;
                                    doc.Add(p);
                                }
                                break;
                        }
                        //discount (applied to order subtotal)
                        if (order.OrderSubTotalDiscountExclTax > decimal.Zero)
                        {
                            switch (order.CustomerTaxDisplayType)
                            {
                                case TaxDisplayType.ExcludingTax:
                                    {
                                        var orderSubTotalDiscountExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountExclTax, order.CurrencyRate);
                                        string orderSubTotalDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderSubTotalDiscountExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);

                                        var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Discount", lang.Id), orderSubTotalDiscountInCustomerCurrencyStr), font);
                                        p.Alignment = Element.ALIGN_RIGHT;
                                        doc.Add(p);
                                    }
                                    break;
                                case TaxDisplayType.IncludingTax:
                                    {
                                        var orderSubTotalDiscountInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountInclTax, order.CurrencyRate);
                                        string orderSubTotalDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderSubTotalDiscountInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);

                                        var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Discount", lang.Id), orderSubTotalDiscountInCustomerCurrencyStr), font);
                                        p.Alignment = Element.ALIGN_RIGHT;
                                        doc.Add(p);
                                    }
                                    break;
                            }
                        }

                        //shipping 
                        if (order.ShippingStatus != ShippingStatus.ShippingNotRequired)
                        {
                            switch (order.CustomerTaxDisplayType)
                            {
                                case TaxDisplayType.ExcludingTax:
                                    {
                                        var orderShippingExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderShippingExclTax, order.CurrencyRate);
                                        string orderShippingExclTaxStr = _priceFormatter.FormatShippingPrice(orderShippingExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);

                                        var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Shipping", lang.Id), orderShippingExclTaxStr), font);
                                        p.Alignment = Element.ALIGN_RIGHT;
                                        doc.Add(p);
                                    }
                                    break;
                                case TaxDisplayType.IncludingTax:
                                    {
                                        var orderShippingInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderShippingInclTax, order.CurrencyRate);
                                        string orderShippingInclTaxStr = _priceFormatter.FormatShippingPrice(orderShippingInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);

                                        var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Shipping", lang.Id), orderShippingInclTaxStr), font);
                                        p.Alignment = Element.ALIGN_RIGHT;
                                        doc.Add(p);
                                    }
                                    break;
                            }
                        }

                        //payment fee
                        if (order.PaymentMethodAdditionalFeeExclTax > decimal.Zero)
                        {
                            switch (order.CustomerTaxDisplayType)
                            {
                                case TaxDisplayType.ExcludingTax:
                                    {
                                        var paymentMethodAdditionalFeeExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.PaymentMethodAdditionalFeeExclTax, order.CurrencyRate);
                                        string paymentMethodAdditionalFeeExclTaxStr = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);

                                        var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.PaymentMethodAdditionalFee", lang.Id), paymentMethodAdditionalFeeExclTaxStr), font);
                                        p.Alignment = Element.ALIGN_RIGHT;
                                        doc.Add(p);
                                    }
                                    break;
                                case TaxDisplayType.IncludingTax:
                                    {
                                        var paymentMethodAdditionalFeeInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.PaymentMethodAdditionalFeeInclTax, order.CurrencyRate);
                                        string paymentMethodAdditionalFeeInclTaxStr = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);

                                        var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.PaymentMethodAdditionalFee", lang.Id), paymentMethodAdditionalFeeInclTaxStr), font);
                                        p.Alignment = Element.ALIGN_RIGHT;
                                        doc.Add(p);
                                    }
                                    break;
                            }
                        }

                        //tax
                        //string taxStr = string.Empty;
                        //var taxRates = new SortedDictionary<decimal, decimal>();
                        //bool displayTax = true;
                        //bool displayTaxRates = true;
                        //if (_taxSettings.HideTaxInOrderSummary && order.CustomerTaxDisplayType == TaxDisplayType.IncludingTax)
                        //{
                        //    displayTax = false;
                        //}
                        //else
                        //{
                        //    if (order.OrderTax == 0 && _taxSettings.HideZeroTax)
                        //    {
                        //        displayTax = false;
                        //        displayTaxRates = false;
                        //    }
                        //    else
                        //    {
                        //        taxRates = order.TaxRatesDictionary;


                        //        displayTaxRates = _taxSettings.DisplayTaxRates && taxRates.Count > 0;
                        //        displayTax = !displayTaxRates;

                        //        var orderTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderTax, order.CurrencyRate);
                        //        taxStr = _priceFormatter.FormatPrice(orderTaxInCustomerCurrency, true, order.CustomerCurrencyCode, false, lang);
                        //    }
                        //}
                        //if (displayTax)
                        //{
                        //    var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Tax", lang.Id), taxStr), font);
                        //    p.Alignment = Element.ALIGN_RIGHT;
                        //    doc.Add(p);
                        //}
                        //if (displayTaxRates)
                        //{
                        //    foreach (var item in taxRates)
                        //    {
                        //        string taxRate = String.Format(_localizationService.GetResource("PDFInvoice.TaxRate", lang.Id), _priceFormatter.FormatTaxRate(item.Key));
                        //        string taxValue = _priceFormatter.FormatPrice(_currencyService.ConvertCurrency(item.Value, order.CurrencyRate), true, order.CustomerCurrencyCode, false, lang);

                        //        var p = new Paragraph(String.Format("{0} {1}", taxRate, taxValue), font);
                        //        p.Alignment = Element.ALIGN_RIGHT;
                        //        doc.Add(p);
                        //    }
                        //}

                        //discount (applied to order total)
                        if (order.OrderDiscount > decimal.Zero)
                        {
                            var orderDiscountInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderDiscount, order.CurrencyRate);
                            string orderDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderDiscountInCustomerCurrency, true, order.CustomerCurrencyCode, false, lang);

                            var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Discount", lang.Id), orderDiscountInCustomerCurrencyStr), font);
                            p.Alignment = Element.ALIGN_RIGHT;
                            doc.Add(p);
                        }

                        //gift cards
                        foreach (var gcuh in order.GiftCardUsageHistory)
                        {
                            string gcTitle = string.Format(_localizationService.GetResource("PDFInvoice.GiftCardInfo", lang.Id), gcuh.GiftCard.GiftCardCouponCode);
                            string gcAmountStr = _priceFormatter.FormatPrice(-(_currencyService.ConvertCurrency(gcuh.UsedValue, order.CurrencyRate)), true, order.CustomerCurrencyCode, false, lang);

                            var p = new Paragraph(String.Format("{0} {1}", gcTitle, gcAmountStr), font);
                            p.Alignment = Element.ALIGN_RIGHT;
                            doc.Add(p);
                        }

                        //reward points
                        if (order.RedeemedRewardPointsEntry != null)
                        {
                            string rpTitle = string.Format(_localizationService.GetResource("PDFInvoice.RewardPoints", lang.Id), -order.RedeemedRewardPointsEntry.Points);
                            string rpAmount = _priceFormatter.FormatPrice(-(_currencyService.ConvertCurrency(order.RedeemedRewardPointsEntry.UsedAmount, order.CurrencyRate)), true, order.CustomerCurrencyCode, false, lang);

                            var p = new Paragraph(String.Format("{0} {1}", rpTitle, rpAmount), font);
                            p.Alignment = Element.ALIGN_RIGHT;
                            doc.Add(p);
                        }

                        //order total
                        var orderTotalInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderTotal, order.CurrencyRate);
                        string orderTotalStr = _priceFormatter.FormatPrice(orderTotalInCustomerCurrency, true, order.CustomerCurrencyCode, false, lang);


                        var pTotal = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.OrderTotal", lang.Id), orderTotalStr), titleFont);
                        pTotal.Alignment = Element.ALIGN_RIGHT;
                        doc.Add(pTotal);

                        #endregion

                        #region Order notes

                        if (_pdfSettings.RenderOrderNotes)
                        {
                            var orderNotes = order.OrderNotes
                                .Where(on => on.DisplayToCustomer)
                                .OrderByDescending(on => on.CreatedOnUtc)
                                .ToList();
                            if (orderNotes.Count > 0)
                            {
                                doc.Add(new Paragraph(_localizationService.GetResource("PDFInvoice.OrderNotes", lang.Id), titleFont));

                                doc.Add(new Paragraph(" "));

                                var notesTable = new PdfPTable(2);
                                notesTable.WidthPercentage = 100f;
                                notesTable.SetWidths(new[] { 30, 70 });

                                //created on
                                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.OrderNotes.CreatedOn", lang.Id), font));
                                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                                notesTable.AddCell(cell);

                                //note
                                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.OrderNotes.Note", lang.Id), font));
                                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                                notesTable.AddCell(cell);

                                foreach (var orderNote in orderNotes)
                                {
                                    cell = new PdfPCell();
                                    cell.AddElement(new Paragraph(TimeZoneInfo.ConvertTimeFromUtc(orderNote.CreatedOnUtc, timeZoneInfo).ToString(), font));
                                    cell.HorizontalAlignment = Element.ALIGN_LEFT;
                                    notesTable.AddCell(cell);

                                    cell = new PdfPCell();
                                    cell.AddElement(new Paragraph(HtmlHelper.ConvertHtmlToPlainText(orderNote.FormatOrderNoteText(), true, true), font));
                                    cell.HorizontalAlignment = Element.ALIGN_LEFT;
                                    notesTable.AddCell(cell);
                                }
                                doc.Add(notesTable);
                            }
                        }

                        #endregion
                    }
                }

                #region Cost Section Table

                /*
                var par = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Sub-Total", lang.Id), _priceFormatter.FormatPrice(invoice.SubTotal)), font);
                par.Alignment = Element.ALIGN_RIGHT;
                doc.Add(par);

                if (invoice.FuelSurcharge.HasValue)
                {
                    par = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.FuelSurcharge", lang.Id), _priceFormatter.FormatPrice(invoice.FuelSurcharge.Value)), font);
                    par.Alignment = Element.ALIGN_RIGHT;
                    doc.Add(par);
                }

                par = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Tax", lang.Id), _priceFormatter.FormatPrice(invoice.Tax)), font);
                par.Alignment = Element.ALIGN_RIGHT;
                doc.Add(par);

                par = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Total", lang.Id), _priceFormatter.FormatPrice(invoice.Total)), font);
                par.Alignment = Element.ALIGN_RIGHT;
                doc.Add(par);
                */

                var costSectionTable = new PdfPTable(2);
                costSectionTable.WidthPercentage = 100f;
                costSectionTable.SetWidths(new[] { 94, 6 }); // should add to 100, last item must match the tables above.

                cell = new PdfPCell();
                cell.Border = Rectangle.NO_BORDER;

                cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Sub-Total", lang.Id), headerAddressFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                costSectionTable.AddCell(cell);

                cell.Phrase = new Phrase(_priceFormatter.FormatPrice(invoice.SubTotal), headerAddressFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                costSectionTable.AddCell(cell);

                if (invoice.FuelSurcharge.HasValue)
                {
                    cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.FuelSurcharge", lang.Id), headerAddressFont);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    costSectionTable.AddCell(cell);

                    cell.Phrase = new Phrase(_priceFormatter.FormatPrice(invoice.FuelSurcharge.Value), headerAddressFont);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    costSectionTable.AddCell(cell);
                }

                cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Discount", lang.Id), headerAddressFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                costSectionTable.AddCell(cell);

                cell.Phrase = new Phrase(_priceFormatter.FormatPrice(invoice.Discount), headerAddressFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                costSectionTable.AddCell(cell);

                cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Tax", lang.Id), headerAddressFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                costSectionTable.AddCell(cell);

                cell.Phrase = new Phrase(_priceFormatter.FormatPrice(invoice.Tax), headerAddressFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                costSectionTable.AddCell(cell);

                cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Total", lang.Id), invoiceHighlightFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                costSectionTable.AddCell(cell);

                cell.Phrase = new Phrase(_priceFormatter.FormatPrice(invoice.Total), invoiceHighlightFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                costSectionTable.AddCell(cell);

                //if (totalRefundedAmount > 0)
                //{
                //    cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Refunded", lang.Id), headerAddressFont);
                //    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                //    costSectionTable.AddCell(cell);

                //    cell.Phrase = new Phrase(_priceFormatter.FormatPrice(totalRefundedAmount), headerAddressFont);
                //    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                //    costSectionTable.AddCell(cell);
                //}

                doc.Add(costSectionTable);

                #endregion

                if (!String.IsNullOrEmpty(invoice.Comment))
                {
                    doc.Add(new Paragraph(""));

                    var commentFont = GetFont();
                    commentFont.Size = 9;
                    doc.Add(new Paragraph(String.Format("Comment:\n{0}", invoice.Comment), commentFont));
                    doc.Add(new Paragraph(" "));
                }

                #region Order notes for SpotsExpress

                if (_pdfSettings.RenderOrderNotes && expressOrders != null && expressOrders.Count() > 0)
                {
                    // starts order notes table on a new page
                    doc.NewPage();

                    var orderNotesPresent = expressOrders.Any(o => o.OrderNotes.Where(on => on.DisplayToCustomer).Count() > 0);
                    if (orderNotesPresent)
                    {
                        // Print order note section title.
                        doc.Add(new Paragraph(_localizationService.GetResource("PDFInvoice.OrderNotes", lang.Id), titleFont));

                        doc.Add(new Paragraph(" "));

                        var notesTable = new PdfPTable(3);
                        notesTable.WidthPercentage = 100f;
                        notesTable.SetWidths(new[] { 15, 15, 70 });
                        notesTable.HeaderRows = 1;

                        #region order note table header

                        // Order #
                        cell = new PdfPCell(new Paragraph(_localizationService.GetResource("PDFInvoice.TableOrder#", lang.Id), font));
                        cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                        cell.HorizontalAlignment = Element.ALIGN_CENTER;
                        notesTable.AddCell(cell);

                        //created on
                        cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.OrderNotes.CreatedOn", lang.Id), font));
                        cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                        cell.HorizontalAlignment = Element.ALIGN_CENTER;
                        notesTable.AddCell(cell);

                        //note
                        cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.OrderNotes.Note", lang.Id), font));
                        cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                        cell.HorizontalAlignment = Element.ALIGN_CENTER;
                        notesTable.AddCell(cell);

                        #endregion

                        foreach (var order in expressOrders)
                        {
                            var orderNotes = order.OrderNotes
                                .Where(on => on.DisplayToCustomer)
                                .OrderByDescending(on => on.CreatedOnUtc)
                                .ToList();

                            cell = new PdfPCell();
                            cell.Rowspan = orderNotes.Count;
                            cell.HorizontalAlignment = Element.ALIGN_LEFT;
                            cell.AddElement(new Paragraph(order.Id.ToString(), font));
                            notesTable.AddCell(cell);

                            foreach (var orderNote in orderNotes)
                            {
                                cell = new PdfPCell();
                                cell.AddElement(new Paragraph(TimeZoneInfo.ConvertTimeFromUtc(orderNote.CreatedOnUtc, timeZoneInfo).ToString(), font));
                                cell.HorizontalAlignment = Element.ALIGN_LEFT;
                                notesTable.AddCell(cell);

                                cell = new PdfPCell();
                                cell.AddElement(new Paragraph(HtmlHelper.ConvertHtmlToPlainText(orderNote.FormatOrderNoteText(), true, true), font));
                                cell.HorizontalAlignment = Element.ALIGN_LEFT;
                                notesTable.AddCell(cell);
                            }
                        }

                        doc.Add(notesTable);
                    }  // if (orderNotesPresent)
                }

                #endregion

            }
        }

        private void populateInvoiceAsPdf(Document doc, Invoice invoice, Language lang, bool useCustomerTimeZone)
        {
            switch ((OrderKind)invoice.OrderKindId)
            {
                case OrderKind.Express:
                    populateExpressInvoiceAsPdf(doc, invoice, lang, useCustomerTimeZone);
                    break;
                case OrderKind.Commerce:
                    populateCommerceInvoiceAsPdf(doc, invoice, lang);
                    break;
                case OrderKind.ExpressMembership:
                default:
                    throw new NotSupportedException();
            }
        }

        /// <summary>
        /// Populate the content of a commerce-order Invoice in a PDF.
        /// </summary>
        /// <param name="doc">Document object that is already opened and associated to a file stream</param>
        /// <param name="orders">Orders</param>
        /// <param name="lang">Language</param>
        //public virtual void PrintCommerceOrdersForStoreOwnersToPdf(Stream stream, IList<Order> orders, Language lang, int storeId, DateTime? start, DateTime? end)
        private void populateCommerceInvoiceAsPdf(Document doc, Invoice invoice, Language lang)
        {
            if (doc == null)
                throw new ArgumentNullException("doc");

            if (invoice == null)
                throw new ArgumentNullException("invoice");

            if (invoice.Orders == null || invoice.Orders.Count == 0)
                throw new ArgumentNullException("orders");

            if (lang == null)
                throw new ArgumentNullException("lang");

            int storeId = invoice.StoreId ?? 0;
            if (storeId <= 1)
                throw new NopException(_localizationService.GetResource("Admin.PdfService.StoreId.Validation"), invoice.StoreId);

            var store = _storeService.GetStoreById(storeId);
            if (store == null)
                throw new ArgumentNullException("store");

            //fonts
            var titleFont = GetFont();
            titleFont.SetStyle(Font.BOLD);
            titleFont.Color = BaseColor.BLACK;
            titleFont.Size = 12;
            var font = GetFont();
            font.Size = 9;
            var highLightFont = GetFont();
            highLightFont.SetStyle(Font.BOLD);
            highLightFont.Color = BaseColor.BLACK;
            highLightFont.Size = 9;

            var emptyBorderlessCell = new PdfPCell();
            emptyBorderlessCell.Border = Rectangle.NO_BORDER;

            #region Header
            // Header table
            var headerTable = new PdfPTable(2);
            headerTable.WidthPercentage = 100f;
            headerTable.SetWidths(new[] { 50, 50 });

            //logo
            var imagePath = _webHelper.MapPath("~/content/images");
            var imageFile = "spotshub-textlogo-print.png";
            byte[] logoPicBinary;
            if (!File.Exists(Path.Combine(imagePath, imageFile)))
            {
                logoPicBinary = new byte[0];
            }
            else
            {
                logoPicBinary = File.ReadAllBytes(Path.Combine(imagePath, imageFile));
            }

            var logoExists = true;
            if (logoPicBinary == null || logoPicBinary.Length == 0)
                logoExists = false;
            //logo
            if (logoExists)
            {
                var logoFilePath = Path.Combine(imagePath, imageFile);
                var logoImg = Image.GetInstance(logoFilePath);
                var cellLogo = new PdfPCell(logoImg);
                cellLogo.Border = Rectangle.NO_BORDER;
                cellLogo.HorizontalAlignment = Element.ALIGN_LEFT;
                cellLogo.PaddingTop = 0f;
                doc.Add(new Paragraph(" "));
                headerTable.AddCell(cellLogo);
            }
            else
            {
                headerTable.AddCell(new PdfPCell());
            }

            var invoiceTitleWordFont = GetFont();
            invoiceTitleWordFont.Size = 16;
            invoiceTitleWordFont.SetStyle(Font.BOLD);
            var cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.Invoice", lang.Id), invoiceTitleWordFont));
            cell.Border = Rectangle.NO_BORDER;
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            cell.PaddingBottom = 10f;
            headerTable.AddCell(cell);
            doc.Add(new Paragraph(" "));
            #endregion

            #region Addresses
            var addressTable = new PdfPTable(2);
            addressTable.WidthPercentage = 100f;
            addressTable.SetWidths(new[] { 50, 50 });

            // first line is: <empty column>  |   Billing to Customer
            addressTable.AddCell(emptyBorderlessCell);

            cell = new PdfPCell();
            cell.Border = Rectangle.NO_BORDER;
            cell.HorizontalAlignment = Element.ALIGN_LEFT;
            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.BillingInformation", lang.Id), titleFont);
            cell.BackgroundColor = BaseColor.LIGHT_GRAY;
            addressTable.AddCell(cell);

            //company address info
            var companyAddress = _addressService.GetAddressById(_pdfSettings.InvoiceCompanyAddressId);
            if (companyAddress != null)
            {
                cell = new PdfPCell();
                cell.Border = Rectangle.NO_BORDER;
                if (_addressSettings.StreetAddressEnabled)
                    cell.AddElement(new Paragraph(companyAddress.Address1, font));
                if (_addressSettings.CityEnabled || _addressSettings.StateProvinceEnabled || _addressSettings.ZipPostalCodeEnabled)
                    cell.AddElement(new Paragraph(String.Format("{0}, {1} {2}", companyAddress.City, companyAddress.StateProvince != null ? companyAddress.StateProvince.GetLocalized(x => x.Abbreviation, lang.Id) : "", companyAddress.ZipPostalCode), font));
                if (_addressSettings.PhoneEnabled)
                    cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Phone", lang.Id), companyAddress.PhoneNumber), font));
                if (!String.IsNullOrEmpty(companyAddress.Email))
                    cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Email", lang.Id), companyAddress.Email), font));
                if (_addressSettings.FaxEnabled && !String.IsNullOrEmpty(companyAddress.FaxNumber))
                    cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Fax", lang.Id), companyAddress.FaxNumber), font));
                if (!String.IsNullOrEmpty(_taxSettings.ExpressGstNumber))
                    cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.GstNumber", lang.Id), _taxSettings.ExpressGstNumber), font));
            }
            else
            {
                cell = new PdfPCell(new Phrase(" "));
                cell.Border = Rectangle.NO_BORDER;
            }
            addressTable.AddCell(cell);
            cell = new PdfPCell();

            //billing info
            cell.Border = Rectangle.NO_BORDER;
            var customer = invoice.Customer;
            if (_addressSettings.CompanyEnabled && !String.IsNullOrEmpty(customer.BillingAddress.Company))
            {
                cell.AddElement(new Paragraph(customer.BillingAddress.Company, font));
            }
            else
            {
                // only display first + last name if company name is empty
                cell.AddElement(new Paragraph(String.Format(customer.GetFullName()), font));
            }

            string streetAddress = "";
            if (_addressSettings.StreetAddressEnabled && _addressSettings.StreetAddress2Enabled && !String.IsNullOrEmpty(customer.BillingAddress.Address2))
            {
                streetAddress = String.Format("{0}-{1}", customer.BillingAddress.Address2, customer.BillingAddress.Address1);
            }
            else if (_addressSettings.StreetAddressEnabled)
            {
                streetAddress = customer.BillingAddress.Address1;
            }

            if (!String.IsNullOrEmpty(streetAddress))
            {
                cell.AddElement(new Paragraph(streetAddress, font));
            }
            if (_addressSettings.CityEnabled || _addressSettings.StateProvinceEnabled || _addressSettings.ZipPostalCodeEnabled)
                cell.AddElement(new Paragraph(String.Format("{0}, {1} {2}", customer.BillingAddress.City, customer.BillingAddress.StateProvince != null ? customer.BillingAddress.StateProvince.GetLocalized(x => x.Abbreviation, lang.Id) : "", customer.BillingAddress.ZipPostalCode), font));

            if (_addressSettings.CellPhoneEnabled && !String.IsNullOrEmpty(customer.BillingAddress.CellPhoneNumber))
                cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.CellPhone", lang.Id), customer.BillingAddress.CellPhoneNumber), font));
            if (_addressSettings.PhoneEnabled && !String.IsNullOrEmpty(customer.BillingAddress.PhoneNumber))
                cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Phone", lang.Id), customer.BillingAddress.PhoneNumber), font));
            if (_addressSettings.FaxEnabled && !String.IsNullOrEmpty(customer.BillingAddress.FaxNumber))
                cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Fax", lang.Id), customer.BillingAddress.FaxNumber), font));
            if (!String.IsNullOrEmpty(customer.BillingAddress.Email))
                cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Email", lang.Id), customer.BillingAddress.Email), font));

            addressTable.AddCell(cell);

            var addressTableCell = new PdfPCell(addressTable);
            addressTableCell.Border = Rectangle.NO_BORDER;
            headerTable.AddCell(addressTableCell);
            #endregion

            #region Invoice info section on Header
            var invoiceInfoTable = new PdfPTable(2);
            invoiceInfoTable.WidthPercentage = 100f;
            invoiceInfoTable.SetWidths(new[] { 60, 40 });

            cell = new PdfPCell();
            cell.Border = Rectangle.NO_BORDER;

            //First line empty
            cell.Phrase = new Phrase(" ", font);
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            invoiceInfoTable.AddCell(cell);

            cell.Phrase = new Phrase(" ", font);
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            invoiceInfoTable.AddCell(cell);

            //Second line invoice number
            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.InvoiceNumber", lang.Id), highLightFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            invoiceInfoTable.AddCell(cell);

            cell.Phrase = new Phrase(invoice.InvoiceNumber, font);
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            invoiceInfoTable.AddCell(cell);

            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Date", lang.Id), highLightFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            invoiceInfoTable.AddCell(cell);

            cell.Phrase = new Phrase(_dateTimeHelper.ConvertToUserTime(invoice.CreatedOnUtc, DateTimeKind.Utc)
                                .ToString("MM/dd/yyyy", new CultureInfo(lang.LanguageCulture)), font);
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            invoiceInfoTable.AddCell(cell);

            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.PeriodInvoiceName", lang.Id), highLightFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            cell.Border = Rectangle.NO_BORDER;
            invoiceInfoTable.AddCell(cell);

            cell.Phrase = new Phrase(invoice.Name, font);
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            cell.Border = Rectangle.NO_BORDER;
            invoiceInfoTable.AddCell(cell);

            //Empty area
            cell.Phrase = new Phrase(" ", font);
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            invoiceInfoTable.AddCell(cell);
            cell.Phrase = new Phrase(" ", font);
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            invoiceInfoTable.AddCell(cell);

            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Due", lang.Id), highLightFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            invoiceInfoTable.AddCell(cell);

            cell.Phrase = new Phrase(_dateTimeHelper.ConvertToUserTime(invoice.DueDate.Value, DateTimeKind.Utc)
                                .ToString("MM/dd/yyyy", new CultureInfo(lang.LanguageCulture)), font);
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            invoiceInfoTable.AddCell(cell);

            var invoiceInfoTableCell = new PdfPCell(invoiceInfoTable);
            invoiceInfoTableCell.Border = Rectangle.NO_BORDER;
            headerTable.AddCell(invoiceInfoTableCell);

            doc.Add(headerTable);
            #endregion

            #region First area
            decimal serviceChargeFee = invoice.ServiceCharge == null ? 0 : invoice.ServiceCharge.Value;
            decimal orderSubtotalExclTax = invoice.Orders.Sum(o => o.OrderSubtotalExclTax);
            decimal orderTotal = invoice.Orders.Sum(o => o.OrderTotal);
            decimal refundOrdersTransactionTotal = 0M;
            decimal discount = invoice.Orders.Sum(o => o.OrderSubTotalDiscountExclTax);
            decimal orderTotalWithDiscount = orderSubtotalExclTax - discount;
            decimal netTransactionTotal = orderTotal;

            var refundOrders = invoice.Orders.Where(o => o.PaymentStatusId == (int)PaymentStatus.Refunded || o.PaymentStatusId == (int)PaymentStatus.PartiallyRefunded).ToList();
            decimal refundOrderDiscount = 0M;
            decimal refundOrderSubtotalExclTax = 0M;
            decimal refundOrderTotalWithDiscount = 0M;
            if (refundOrders != null && refundOrders.Count > 0)
            {
                refundOrderDiscount = refundOrders.Where(o => o.PaymentStatusId == (int)PaymentStatus.Refunded).Sum(o => o.OrderSubTotalDiscountExclTax);
                refundOrderSubtotalExclTax = refundOrders.Where(o => o.PaymentStatusId == (int)PaymentStatus.Refunded).Sum(o => o.OrderSubtotalExclTax);
                if (refundOrders.Any(o => o.PaymentStatus == PaymentStatus.PartiallyRefunded))
                {
                    var partiallyRefundOPVList = refundOrders.Where(o => o.PaymentStatus == PaymentStatus.PartiallyRefunded)
                                                                            .SelectMany(o => o.OrderProductVariants.Where(opv => opv.IsRefund == 1)).ToList();
                    var partiallyRefundOPVNotHasRefundQuantity = partiallyRefundOPVList.Where(opv => !opv.RefundQuantity.HasValue).ToList();
                    var partiallyRefundOPVWithRefundQuantity = partiallyRefundOPVList.Where(opv => opv.RefundQuantity.HasValue).ToList();

                    //get dicount and priceExclTax if opv does not have refund quantity
                    decimal partiallyRefundOrderSubtotalExclTax = partiallyRefundOPVNotHasRefundQuantity.Sum(opv => opv.PriceExclTax);
                    decimal partiallyRefundOrderDiscount = partiallyRefundOPVNotHasRefundQuantity.Sum(opv => opv.DiscountAmountExclTax);
                    var subtotalExclTaxList = new List<decimal>();
                    var discountExclTaxList = new List<decimal>();

                    //if opv has refund quantity
                    foreach (var propv in partiallyRefundOPVWithRefundQuantity)
                    {
                        decimal priceExclTax = propv.UnitPriceExclTax * propv.RefundQuantity.Value;
                        decimal discountExclTax = propv.DiscountAmountExclTax * (propv.RefundQuantity.Value / propv.Quantity);
                        subtotalExclTaxList.Add(priceExclTax);
                        discountExclTaxList.Add(discountExclTax);
                    }
                    partiallyRefundOrderSubtotalExclTax += subtotalExclTaxList.Sum();
                    partiallyRefundOrderDiscount += discountExclTaxList.Sum();

                    refundOrderSubtotalExclTax += partiallyRefundOrderSubtotalExclTax;
                    refundOrderDiscount += partiallyRefundOrderDiscount;
                }

                refundOrderTotalWithDiscount = refundOrderSubtotalExclTax - refundOrderDiscount;
                refundOrdersTransactionTotal = refundOrders.Sum(o => o.RefundedAmount);
                netTransactionTotal = orderTotal - refundOrdersTransactionTotal;
            }

            var culture = new CultureInfo(_workContext.WorkingLanguage.LanguageCulture);
            bool isDiscount = discount > decimal.Zero;

            #region Title
            //store info
            var titleTable = new PdfPTable(2);
            titleTable.WidthPercentage = 100f;
            titleTable.SetWidths(new[] { 50, 50 });

            cell = new PdfPCell();
            cell.Border = Rectangle.NO_BORDER;
            cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.SalesRecord", lang.Id)), titleFont));
            cell.PaddingBottom = 3f;
            titleTable.AddCell(cell);

            //Null cell
            cell = new PdfPCell();
            cell.Border = Rectangle.NO_BORDER;
            cell.PaddingBottom = 3f;
            titleTable.AddCell(cell);

            doc.Add(titleTable);
            #endregion

            decimal orderTax = 0;
            var surchargeTaxList = new List<Surcharge>();
            if (invoice.Orders != null && invoice.Orders.Count > 0)
            {
                #region Order list
                var ordersTable = new PdfPTable(isDiscount ? 9 : 7);
                ordersTable.WidthPercentage = 100f;
                ordersTable.SetWidths(isDiscount ? new[] { 8, 15, 20, 10, 8, 9, 10, 10, 10 } : new[] { 10, 18, 24, 14, 11, 12, 11 });

                //order identifier
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.TableOrder#", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                ordersTable.AddCell(cell);

                //order time
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.OrderTime", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                ordersTable.AddCell(cell);

                //Product name
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductName", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                ordersTable.AddCell(cell);

                //SKU
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.SKU", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                ordersTable.AddCell(cell);

                //price
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductPrice", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                ordersTable.AddCell(cell);

                //order quantity
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductQuantity", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                ordersTable.AddCell(cell);

                //Total price
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductSubTotal", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                ordersTable.AddCell(cell);

                if (isDiscount)
                {
                    //Discount Amount
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.DiscountAmount", lang.Id), highLightFont));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    ordersTable.AddCell(cell);

                    //Subtotal
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductTotal", lang.Id), highLightFont));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    ordersTable.AddCell(cell);
                }

                foreach (var order in invoice.Orders)
                {
                    int count = order.OrderProductVariants.Count();
                    if (count > 0 && order.OrderProductVariants != null)
                    {
                        int j = 0;
                        foreach (var opv in order.OrderProductVariants)
                        {
                            var pv = opv.ProductVariant;
                            j += 1;
                            if (j == 1)
                            {
                                //order Id
                                cell = new PdfPCell(new Phrase(order.Id.ToString(), font));
                                cell.Rowspan = count;
                                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                                ordersTable.AddCell(cell);

                                //order time
                                cell = new PdfPCell(new Paragraph(_dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, DateTimeKind.Utc).ToString("MM/dd/yyyy h:mm tt", new CultureInfo(lang.LanguageCulture)), font));
                                cell.Rowspan = count;
                                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                                ordersTable.AddCell(cell);
                            }

                            //product name
                            string name = "";
                            var attributesFont = GetFont();
                            attributesFont.SetStyle(Font.ITALIC);
                            if (!String.IsNullOrEmpty(pv.GetLocalized(x => x.Name, lang.Id)))
                                name = string.Format("{0} ({1})", pv.Product.GetLocalized(x => x.Name, lang.Id), pv.GetLocalized(x => x.Name, lang.Id));
                            else
                                name = pv.Product.GetLocalized(x => x.Name, lang.Id);
                            cell = new PdfPCell();
                            Paragraph p1 = new Paragraph(name, font);
                            p1.Alignment = Element.ALIGN_CENTER;
                            cell.AddElement(p1);
                            if (!String.IsNullOrEmpty(opv.AttributeDescription) && !opv.AttributeDescription.Contains(_localizationService.GetResource("PDFInvoice.CustomText")))
                            {
                                var attributesParagraph = new Phrase(HtmlHelper.ConvertHtmlToPlainText(opv.AttributeDescription, true, true), attributesFont);
                                Paragraph p2 = new Paragraph(attributesParagraph);
                                p2.Alignment = Element.ALIGN_CENTER;
                                cell.AddElement(p2);
                            }
                            ordersTable.AddCell(cell);

                            //SKU
                            cell = new PdfPCell(new Phrase(pv.Sku ?? String.Empty, font));
                            cell.HorizontalAlignment = Element.ALIGN_CENTER;
                            cell.Rowspan = 1;//Back to 1
                            ordersTable.AddCell(cell);

                            //price
                            string unitPrice = string.Empty;
                            switch (order.CustomerTaxDisplayType)
                            {
                                case TaxDisplayType.ExcludingTax:
                                    {
                                        var opvUnitPriceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(opv.UnitPriceExclTax, order.CurrencyRate);
                                        unitPrice = _priceFormatter.FormatPrice(opvUnitPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                                    }
                                    break;
                                case TaxDisplayType.IncludingTax:
                                    {
                                        var opvUnitPriceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(opv.UnitPriceInclTax, order.CurrencyRate);
                                        unitPrice = _priceFormatter.FormatPrice(opvUnitPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);
                                    }
                                    break;
                            }
                            cell = new PdfPCell(new Phrase(unitPrice, font));
                            cell.HorizontalAlignment = Element.ALIGN_CENTER;
                            ordersTable.AddCell(cell);

                            //quantity
                            cell = new PdfPCell(new Phrase(opv.Quantity.ToString(), font));
                            cell.HorizontalAlignment = Element.ALIGN_CENTER;
                            ordersTable.AddCell(cell);

                            //total
                            string subTotal = string.Empty;
                            switch (order.CustomerTaxDisplayType)
                            {
                                case TaxDisplayType.ExcludingTax:
                                    {
                                        var opvPriceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(opv.PriceExclTax, order.CurrencyRate);
                                        subTotal = _priceFormatter.FormatPrice(opvPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                                    }
                                    break;
                                case TaxDisplayType.IncludingTax:
                                    {
                                        var opvPriceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(opv.PriceInclTax, order.CurrencyRate);
                                        subTotal = _priceFormatter.FormatPrice(opvPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);
                                    }
                                    break;
                            }
                            cell = new PdfPCell(new Phrase(subTotal, font));
                            cell.HorizontalAlignment = Element.ALIGN_CENTER;
                            ordersTable.AddCell(cell);

                            if (j == 1)
                            {
                                //discount (applied to order subtotal)
                                if (isDiscount)
                                {
                                    string orderSubTotalDiscountInCustomerCurrencyStr = string.Empty;
                                    string orderSubTotalInCustomerCurrencyStr = string.Empty;
                                    switch (order.CustomerTaxDisplayType)
                                    {
                                        case TaxDisplayType.ExcludingTax:
                                            {
                                                var orderSubTotalDiscountExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountExclTax, order.CurrencyRate);
                                                orderSubTotalDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderSubTotalDiscountExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                                                var orderSubTotalExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalExclTax, order.CurrencyRate);
                                                orderSubTotalInCustomerCurrencyStr = _priceFormatter.FormatPrice(orderSubTotalExclTaxInCustomerCurrency - orderSubTotalDiscountExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                                            }
                                            break;
                                        case TaxDisplayType.IncludingTax:
                                            {
                                                var orderSubTotalDiscountInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountInclTax, order.CurrencyRate);
                                                orderSubTotalDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderSubTotalDiscountInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);
                                                var orderSubTotalInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalInclTax, order.CurrencyRate);
                                                orderSubTotalInCustomerCurrencyStr = _priceFormatter.FormatPrice(orderSubTotalInclTaxInCustomerCurrency - orderSubTotalDiscountInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                                            }
                                            break;
                                    }
                                    //discount
                                    cell = new PdfPCell(new Phrase(orderSubTotalDiscountInCustomerCurrencyStr, font));
                                    cell.Rowspan = count;
                                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                                    ordersTable.AddCell(cell);

                                    //subtotal
                                    cell = new PdfPCell(new Phrase(orderSubTotalInCustomerCurrencyStr, font));
                                    cell.Rowspan = count;
                                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                                    ordersTable.AddCell(cell);
                                }
                            }
                        }

                        //tax
                        decimal taxAmount = 0;
                        bool displayTax = true;
                        bool displayTaxRates = true;
                        var surcharges = _taxSerivce.GetSurchargesByOrder(order).ToList();
                        if (_taxSettings.HideTaxInOrderSummary && order.CustomerTaxDisplayType == TaxDisplayType.IncludingTax)
                        {
                            displayTax = false;
                        }
                        else
                        {
                            if (order.OrderTax == 0 && _taxSettings.HideZeroTax)
                            {
                                displayTax = false;
                                displayTaxRates = false;
                            }
                            else
                            {
                                displayTaxRates = _taxSettings.DisplayTaxRates && surcharges.Count > 0;
                                displayTax = !displayTaxRates;
                            }
                        }
                        if (displayTax)
                        {
                            taxAmount = _currencyService.ConvertCurrency(order.OrderTax, order.CurrencyRate);
                            //Get tax if there is order does not have tax rate
                            orderTax = orderTax + taxAmount;
                        }
                        if (displayTaxRates && surcharges != null)
                        {
                            surchargeTaxList.AddRange(surcharges);
                        }
                    }
                }
                doc.Add(ordersTable);
                #endregion

                #region prducts total price
                //subtotal
                var costSectionTable = new PdfPTable(2);
                costSectionTable.WidthPercentage = 100f;
                costSectionTable.SetWidths(new[] { 92, 8 }); // should add to 100, last item must match the tables above.

                cell = new PdfPCell();
                cell.Border = Rectangle.NO_BORDER;

                cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.TotalSales", lang.Id), highLightFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                costSectionTable.AddCell(cell);

                cell.Phrase = new Phrase(_priceFormatter.FormatPrice(orderTotalWithDiscount, true, false), font);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                costSectionTable.AddCell(cell);

                //No tax rates
                if (orderTax > 0)
                {
                    cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Tax", lang.Id), highLightFont);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    costSectionTable.AddCell(cell);

                    cell.Phrase = new Phrase(_priceFormatter.FormatPrice(orderTax, true, false), font);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    costSectionTable.AddCell(cell);
                }
                //Have rates
                if (surchargeTaxList.Count > 0)
                {
                    foreach (var tax in surchargeTaxList.ToTaxes().ToDistinctTypes().OrderBy(t => t.SurchargeTypeId))
                    {
                        string taxRate = String.Format(_localizationService.GetResource("PDFInvoice.TaxRate", lang.Id), _priceFormatter.FormatTaxRate(tax, false, true));
                        cell.Phrase = new Phrase(taxRate, highLightFont);
                        cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                        costSectionTable.AddCell(cell);

                        cell.Phrase = new Phrase(_priceFormatter.FormatPrice(tax.Value, true, false), font);
                        cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                        costSectionTable.AddCell(cell);
                    }
                }

                //final
                cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.TransactionTotal", lang.Id), highLightFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                cell.Border = Rectangle.TOP_BORDER;
                costSectionTable.AddCell(cell);

                cell.Phrase = new Phrase(_priceFormatter.FormatPrice(orderTotal, true, false), font);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                costSectionTable.AddCell(cell);

                doc.Add(costSectionTable);
                #endregion
            }
            #endregion

            #region Second Region

            if (refundOrders != null && refundOrders.Count > 0)
            {
                #region Refund Order Title
                //store info
                var refundOrdertitleTable = new PdfPTable(2);
                refundOrdertitleTable.WidthPercentage = 100f;
                refundOrdertitleTable.SetWidths(new[] { 50, 50 });

                cell = new PdfPCell();
                cell.Border = Rectangle.NO_BORDER;
                cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.ReturnsRecord", lang.Id)), titleFont));
                cell.PaddingBottom = 3f;
                refundOrdertitleTable.AddCell(cell);

                //Null cell
                cell = new PdfPCell();
                cell.Border = Rectangle.NO_BORDER;
                cell.PaddingBottom = 3f;
                refundOrdertitleTable.AddCell(cell);
                doc.Add(refundOrdertitleTable);
                #endregion

                #region Refund orders list
                var refundOrdersDiscount = refundOrders.Sum(o => o.OrderSubTotalDiscountExclTax);
                bool isRefundOrdersDiscount = refundOrdersDiscount > decimal.Zero;
                var refundOrdersTable = new PdfPTable(isDiscount ? 9 : 7);
                refundOrdersTable.WidthPercentage = 100f;
                refundOrdersTable.SetWidths(isRefundOrdersDiscount ? new[] { 8, 15, 20, 10, 8, 9, 10, 10, 10 } : new[] { 10, 18, 24, 14, 11, 12, 11 });

                //order identifier
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.TableOrder#", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                refundOrdersTable.AddCell(cell);

                //order time
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.OrderTime", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                refundOrdersTable.AddCell(cell);

                //Product name
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductName", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                refundOrdersTable.AddCell(cell);

                //SKU
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.SKU", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                refundOrdersTable.AddCell(cell);

                //price
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductPrice", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                refundOrdersTable.AddCell(cell);

                //order quantity
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductQuantity", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                refundOrdersTable.AddCell(cell);

                //Total price
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductSubTotal", lang.Id), highLightFont));
                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                refundOrdersTable.AddCell(cell);

                if (isRefundOrdersDiscount)
                {
                    //Discount Amount
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.DiscountAmount", lang.Id), highLightFont));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    refundOrdersTable.AddCell(cell);

                    //Subtotal
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductTotal", lang.Id), highLightFont));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    refundOrdersTable.AddCell(cell);
                }

                decimal refundOrderTax = 0;
                var refundSurchargeTaxList = new List<Surcharge>();
                foreach (var order in refundOrders)
                {
                    var orderProductVariantList = order.OrderProductVariants.ToList();
                    if (order.PaymentStatus == PaymentStatus.PartiallyRefunded)
                    {
                        orderProductVariantList = orderProductVariantList.Where(opvl => opvl.IsRefund == 1).ToList();
                    }
                    int refundOrderProductVariantsCount = orderProductVariantList.Count;
                    if (refundOrderProductVariantsCount > 0 && orderProductVariantList != null)
                    {
                        int k = 0;
                        foreach (var opv in orderProductVariantList)
                        {
                            var pv = opv.ProductVariant;
                            k += 1;
                            if (k == 1)
                            {
                                //order Id
                                cell = new PdfPCell(new Phrase(order.Id.ToString(), font));
                                cell.Rowspan = refundOrderProductVariantsCount;
                                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                                refundOrdersTable.AddCell(cell);

                                //order time
                                cell = new PdfPCell(new Paragraph(_dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, DateTimeKind.Utc).ToString("MM/dd/yyyy h:mm tt", new CultureInfo(lang.LanguageCulture)), font));
                                cell.Rowspan = refundOrderProductVariantsCount;
                                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                                refundOrdersTable.AddCell(cell);
                            }

                            //product name
                            string name = "";
                            var attributesFont = GetFont();
                            attributesFont.SetStyle(Font.ITALIC);
                            if (!String.IsNullOrEmpty(pv.GetLocalized(x => x.Name, lang.Id)))
                                name = string.Format("{0} ({1})", pv.Product.GetLocalized(x => x.Name, lang.Id), pv.GetLocalized(x => x.Name, lang.Id));
                            else
                                name = pv.Product.GetLocalized(x => x.Name, lang.Id);
                            cell = new PdfPCell();
                            Paragraph p1 = new Paragraph(name, font);
                            p1.Alignment = Element.ALIGN_CENTER;
                            var attributesParagraph = new Phrase(HtmlHelper.ConvertHtmlToPlainText(opv.AttributeDescription, true, true), attributesFont);
                            Paragraph p2 = new Paragraph(attributesParagraph);
                            p2.Alignment = Element.ALIGN_CENTER;
                            cell.AddElement(p1);
                            cell.AddElement(p2);
                            refundOrdersTable.AddCell(cell);

                            //SKU
                            cell = new PdfPCell(new Phrase(pv.Sku ?? String.Empty, font));
                            cell.HorizontalAlignment = Element.ALIGN_CENTER;
                            cell.Rowspan = 1;//Back to 1
                            refundOrdersTable.AddCell(cell);

                            //price
                            string unitPrice = string.Empty;
                            switch (order.CustomerTaxDisplayType)
                            {
                                case TaxDisplayType.ExcludingTax:
                                    {
                                        var opvUnitPriceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(opv.UnitPriceExclTax, order.CurrencyRate);
                                        unitPrice = _priceFormatter.FormatPrice(opvUnitPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                                    }
                                    break;
                                case TaxDisplayType.IncludingTax:
                                    {
                                        var opvUnitPriceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(opv.UnitPriceInclTax, order.CurrencyRate);
                                        unitPrice = _priceFormatter.FormatPrice(opvUnitPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);
                                    }
                                    break;
                            }
                            cell = new PdfPCell(new Phrase(unitPrice, font));
                            cell.HorizontalAlignment = Element.ALIGN_CENTER;
                            refundOrdersTable.AddCell(cell);

                            //quantity
                            int quantity = opv.RefundQuantity.HasValue ? opv.RefundQuantity.Value : opv.Quantity;
                            cell = new PdfPCell(new Phrase(quantity.ToString(), font));
                            cell.HorizontalAlignment = Element.ALIGN_CENTER;
                            refundOrdersTable.AddCell(cell);

                            //total
                            string subTotal = string.Empty;
                            switch (order.CustomerTaxDisplayType)
                            {
                                case TaxDisplayType.ExcludingTax:
                                    {
                                        decimal priceExclTax = opv.RefundQuantity.HasValue ? opv.UnitPriceExclTax * quantity : opv.PriceExclTax;
                                        var opvPriceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(priceExclTax, order.CurrencyRate);
                                        subTotal = _priceFormatter.FormatPrice(opvPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                                    }
                                    break;
                                case TaxDisplayType.IncludingTax:
                                    {
                                        decimal priceInclTax = opv.RefundQuantity.HasValue ? opv.UnitPriceInclTax * quantity : opv.PriceInclTax;
                                        var opvPriceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(priceInclTax, order.CurrencyRate);
                                        subTotal = _priceFormatter.FormatPrice(opvPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);
                                    }
                                    break;
                            }
                            cell = new PdfPCell(new Phrase(subTotal, font));
                            cell.HorizontalAlignment = Element.ALIGN_CENTER;
                            refundOrdersTable.AddCell(cell);

                            if (k == 1)
                            {
                                if (isRefundOrdersDiscount)
                                {
                                    string orderSubTotalDiscountInCustomerCurrencyStr = string.Empty;
                                    string orderSubTotalInCustomerCurrencyStr = string.Empty;
                                    var discountAmountList = new List<decimal>();
                                    switch (order.CustomerTaxDisplayType)
                                    {
                                        case TaxDisplayType.ExcludingTax:
                                            {
                                                //need improvment when speicial price occur or gift card
                                                decimal orderSubTotalDiscountExcelTax = 0;
                                                var opvRefundList = order.OrderProductVariants.Where(x => x.RefundQuantity.HasValue).ToList();
                                                if (opvRefundList == null || opvRefundList.Count == 0)
                                                {
                                                    orderSubTotalDiscountExcelTax = order.OrderSubTotalDiscountExclTax;
                                                }
                                                else
                                                {
                                                    foreach (var item in opvRefundList)
                                                    {
                                                        decimal opvDiscountAmount = item.RefundQuantity.Value * item.DiscountAmountExclTax / item.Quantity;
                                                        discountAmountList.Add(opvDiscountAmount);
                                                    }
                                                    orderSubTotalDiscountExcelTax = discountAmountList.Sum();
                                                }

                                                var orderSubTotalDiscountExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderSubTotalDiscountExcelTax, order.CurrencyRate);
                                                orderSubTotalDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderSubTotalDiscountExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                                                var orderSubTotalExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalExclTax, order.CurrencyRate);
                                                orderSubTotalInCustomerCurrencyStr = _priceFormatter.FormatPrice(orderSubTotalExclTaxInCustomerCurrency - orderSubTotalDiscountExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                                            }
                                            break;
                                        case TaxDisplayType.IncludingTax:
                                            {
                                                decimal orderSubTotalDiscountInclTax = 0;
                                                var opvRefundList = order.OrderProductVariants.Where(x => x.RefundQuantity.HasValue).ToList();
                                                if (opvRefundList == null || opvRefundList.Count == 0)
                                                {
                                                    orderSubTotalDiscountInclTax = order.OrderSubTotalDiscountInclTax;
                                                }
                                                else
                                                {
                                                    foreach (var item in opvRefundList)
                                                    {
                                                        decimal opvDiscountAmount = item.RefundQuantity.Value * item.DiscountAmountInclTax / item.Quantity;
                                                        discountAmountList.Add(opvDiscountAmount);
                                                    }
                                                    orderSubTotalDiscountInclTax = discountAmountList.Sum();
                                                }

                                                var orderSubTotalDiscountInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderSubTotalDiscountInclTax, order.CurrencyRate);
                                                orderSubTotalDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderSubTotalDiscountInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);
                                                var orderSubTotalInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalInclTax, order.CurrencyRate);
                                                orderSubTotalInCustomerCurrencyStr = _priceFormatter.FormatPrice(orderSubTotalInclTaxInCustomerCurrency - orderSubTotalDiscountInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                                            }
                                            break;
                                    }
                                    //discount
                                    cell = new PdfPCell(new Phrase(orderSubTotalDiscountInCustomerCurrencyStr, font));
                                    cell.Rowspan = refundOrderProductVariantsCount;
                                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                                    refundOrdersTable.AddCell(cell);

                                    //subtotal
                                    cell = new PdfPCell(new Phrase(orderSubTotalInCustomerCurrencyStr, font));
                                    cell.Rowspan = refundOrderProductVariantsCount;
                                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                                    refundOrdersTable.AddCell(cell);
                                }
                            }
                        }
                    }
                    //tax
                    decimal taxAmount = 0;
                    bool displayTax = true;
                    bool displayTaxRates = true;
                    var surcharges = _taxSerivce.GetSurchargesByOrder(order).ToList();

                    if (_taxSettings.HideTaxInOrderSummary && order.CustomerTaxDisplayType == TaxDisplayType.IncludingTax)
                    {
                        displayTax = false;
                    }
                    else
                    {
                        if (order.OrderTax == 0 && _taxSettings.HideZeroTax)
                        {
                            displayTax = false;
                            displayTaxRates = false;
                        }
                        else
                        {
                            displayTaxRates = _taxSettings.DisplayTaxRates && surcharges.Count > 0;
                            displayTax = !displayTaxRates;
                        }
                    }
                    if (displayTax)
                    {
                        var refundOrderTaxTotalAmount = orderProductVariantList.Sum(o => o.PriceInclTax) - orderProductVariantList.Sum(o => o.PriceExclTax);
                        taxAmount = _currencyService.ConvertCurrency(refundOrderTaxTotalAmount, order.CurrencyRate);
                        //Get tax if there is order does not have tax rate
                        refundOrderTax = refundOrderTax + taxAmount;
                    }
                    if (displayTaxRates && surcharges != null)
                    {
                        if (order.PaymentStatus == PaymentStatus.PartiallyRefunded)
                        {
                            foreach (var opvl in orderProductVariantList)
                            {
                                var partiallyRefundOrderTaxSurcharge = _taxSerivce.GetSurchargesByOrderProductVariant(opvl).ToList();
                                if (opvl.RefundQuantity.HasValue && opvl.RefundQuantity.Value > 0 && opvl.RefundQuantity.Value < opvl.Quantity)
                                {
                                    partiallyRefundOrderTaxSurcharge.ForEach(p => p.Value = p.Value * opvl.RefundQuantity.Value / opvl.Quantity);
                                }
                                refundSurchargeTaxList.AddRange(partiallyRefundOrderTaxSurcharge);
                            }
                        }
                        else
                        {
                            refundSurchargeTaxList.AddRange(surcharges);
                        }
                    }
                }
                doc.Add(refundOrdersTable);
                #endregion

                #region return total price
                //subtotal
                var refundCostSectionTable = new PdfPTable(2);
                refundCostSectionTable.WidthPercentage = 100f;
                refundCostSectionTable.SetWidths(new[] { 92, 8 }); // should add to 100, last item must match the tables above.

                cell = new PdfPCell();
                cell.Border = Rectangle.NO_BORDER;

                cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Return", lang.Id), highLightFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                refundCostSectionTable.AddCell(cell);

                cell.Phrase = new Phrase(_priceFormatter.FormatPrice(refundOrderTotalWithDiscount, true, false), font);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                refundCostSectionTable.AddCell(cell);

                //return tax
                //No tax rates
                if (refundOrderTax > 0)
                {
                    cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Tax", lang.Id), highLightFont);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    refundCostSectionTable.AddCell(cell);

                    cell.Phrase = new Phrase(_priceFormatter.FormatPrice(refundOrderTax, true, false), font);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    refundCostSectionTable.AddCell(cell);
                }
                //Have rates
                if (refundSurchargeTaxList.Count > 0)
                {
                    foreach (var tax in refundSurchargeTaxList.ToTaxes().ToDistinctTypes().OrderBy(t => t.SurchargeTypeId))
                    {
                        string taxRate = String.Format(_localizationService.GetResource("PDFInvoice.TaxRate", lang.Id), _priceFormatter.FormatTaxRate(tax, false, true));
                        cell.Phrase = new Phrase(taxRate, highLightFont);
                        cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                        refundCostSectionTable.AddCell(cell);

                        cell.Phrase = new Phrase(_priceFormatter.FormatPrice(tax.Value, true, false), font);
                        cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                        refundCostSectionTable.AddCell(cell);
                    }

                    var partiallyRefundOPVWithRefundQuantity = refundOrders.Where(o => o.PaymentStatus == PaymentStatus.PartiallyRefunded)
                                                                            .SelectMany(o => o.OrderProductVariants.Where(opv => opv.IsRefund == 1 && opv.RefundQuantity.HasValue)).ToList();
                    foreach (var opvl in partiallyRefundOPVWithRefundQuantity)
                    {
                        if (opvl.RefundQuantity.Value > 0 && opvl.RefundQuantity.Value < opvl.Quantity)
                        {
                            //quantity-- not change database
                            var partiallyRefundOrderTaxSurcharge = _taxSerivce.GetSurchargesByOrderProductVariant(opvl).ToList();

                            //return back -- not change database. Need improvement.
                            partiallyRefundOrderTaxSurcharge.ForEach(p => p.Value = p.Value * opvl.Quantity / opvl.RefundQuantity.Value);
                        }
                    }
                }

                //return transaction total
                cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.ReturnTransactionTotal", lang.Id), highLightFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                cell.Border = Rectangle.TOP_BORDER;
                refundCostSectionTable.AddCell(cell);

                cell.Phrase = new Phrase(_priceFormatter.FormatPrice(refundOrdersTransactionTotal, true, false), font);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                refundCostSectionTable.AddCell(cell);

                //null cell
                //New section for no border
                cell.Border = Rectangle.NO_BORDER;
                cell.Phrase = new Phrase(" ", font);
                refundCostSectionTable.AddCell(cell);
                cell.Phrase = new Phrase(" ", font);
                refundCostSectionTable.AddCell(cell);
                cell.Phrase = new Phrase(" ", font);
                refundCostSectionTable.AddCell(cell);
                cell.Phrase = new Phrase(" ", font);
                refundCostSectionTable.AddCell(cell);

                //Total sales
                cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.NetSales", lang.Id), highLightFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                refundCostSectionTable.AddCell(cell);

                var netSales = orderTotalWithDiscount - refundOrderTotalWithDiscount;
                cell.Phrase = new Phrase(_priceFormatter.FormatPrice(netSales, true, false), font);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                refundCostSectionTable.AddCell(cell);

                //net tax
                //No tax rates
                if (refundOrderTax > 0 || orderTax > 0)
                {
                    cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Tax", lang.Id), highLightFont);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    refundCostSectionTable.AddCell(cell);

                    cell.Phrase = new Phrase(_priceFormatter.FormatPrice(orderTax - refundOrderTax, true, false), font);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    refundCostSectionTable.AddCell(cell);
                }
                //Have rates
                if (refundSurchargeTaxList.Count > 0)
                {
                    var orderProductVariantNoRefundList = invoice.Orders.SelectMany(o => o.OrderProductVariants.Where(opv => opv.IsRefund != 1)).ToList();
                    var surchargeList = new List<Surcharge>();
                    foreach (var item in orderProductVariantNoRefundList)
                    {
                        surchargeList.AddRange(_taxSerivce.GetSurchargesByOrderProductVariant(item));
                    }
                    //Not return all quantity
                    var partiallyRefundOPVWithRefundQuantity = refundOrders.Where(o => o.PaymentStatus == PaymentStatus.PartiallyRefunded)
                                                                            .SelectMany(o => o.OrderProductVariants.Where(opv => opv.IsRefund == 1 && opv.RefundQuantity.HasValue)).ToList();
                    bool hasValidRefundQuantity = false;
                    foreach (var opvl in partiallyRefundOPVWithRefundQuantity)
                    {
                        if (opvl.RefundQuantity.Value > 0 && opvl.RefundQuantity.Value < opvl.Quantity)
                        {
                            //quantity-- not change database
                            decimal less = opvl.Quantity - opvl.RefundQuantity.Value;
                            var partiallyRefundOrderTaxSurcharge = _taxSerivce.GetSurchargesByOrderProductVariant(opvl).ToList();
                            partiallyRefundOrderTaxSurcharge.ForEach(p => p.Value = p.Value * less / opvl.Quantity);
                            surchargeList.AddRange(partiallyRefundOrderTaxSurcharge);

                            //return back -- not change database. Need improvement.
                            hasValidRefundQuantity = true;
                        }
                    }

                    foreach (var tax in surchargeList.ToTaxes().ToDistinctTypes().OrderBy(t => t.SurchargeTypeId))
                    {
                        string taxRate = String.Format(_localizationService.GetResource("PDFInvoice.TaxRate", lang.Id), _priceFormatter.FormatTaxRate(tax, false, true));
                        cell.Phrase = new Phrase(taxRate, highLightFont);
                        cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                        refundCostSectionTable.AddCell(cell);

                        cell.Phrase = new Phrase(_priceFormatter.FormatPrice(tax.Value, true, false), font);
                        cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                        refundCostSectionTable.AddCell(cell);
                    }

                    if (hasValidRefundQuantity)
                    {
                        foreach (var opvl in partiallyRefundOPVWithRefundQuantity)
                        {
                            if (opvl.RefundQuantity.Value > 0 && opvl.RefundQuantity.Value < opvl.Quantity)
                            {
                                //quantity-- not change database
                                decimal less = opvl.Quantity - opvl.RefundQuantity.Value;
                                var partiallyRefundOrderTaxSurcharge = _taxSerivce.GetSurchargesByOrderProductVariant(opvl).ToList();

                                //return back -- not change database. Need improvement.
                                partiallyRefundOrderTaxSurcharge.ForEach(p => p.Value = p.Value * opvl.Quantity / less);
                            }
                        }
                    }
                }

                //final
                cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.NetTransactionTotal", lang.Id) + ":", highLightFont);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                cell.Border = Rectangle.TOP_BORDER;
                refundCostSectionTable.AddCell(cell);

                cell.Phrase = new Phrase(_priceFormatter.FormatPrice(netTransactionTotal, true, false), font);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                refundCostSectionTable.AddCell(cell);

                doc.Add(refundCostSectionTable);
                #endregion
            }
            else
            {
                doc.Add(new Paragraph(" "));
            }

            #endregion

            #region Third area

            #region SpotsHUB Title
            //store info
            var spotsHUBtitleTable = new PdfPTable(2);
            spotsHUBtitleTable.WidthPercentage = 100f;
            spotsHUBtitleTable.SetWidths(new[] { 50, 50 });

            cell = new PdfPCell();
            cell.Border = Rectangle.NO_BORDER;
            cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.EcommerceFees", lang.Id)), titleFont));
            cell.PaddingBottom = 3f;
            spotsHUBtitleTable.AddCell(cell);

            //Null cell
            cell = new PdfPCell();
            cell.Border = Rectangle.NO_BORDER;
            cell.PaddingBottom = 3f;
            spotsHUBtitleTable.AddCell(cell);
            doc.Add(spotsHUBtitleTable);
            #endregion

            #region Company item info
            var companyItemTable = new PdfPTable(5);
            companyItemTable.WidthPercentage = 100f;
            companyItemTable.SetWidths(new[] { 15, 40, 25, 15, 15 });

            //item
            cell = new PdfPCell(new Phrase(_localizationService.GetResource(" ", lang.Id), highLightFont));
            cell.BackgroundColor = BaseColor.LIGHT_GRAY;
            companyItemTable.AddCell(cell);

            //description
            cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ServiceFeeType", lang.Id), highLightFont));
            cell.BackgroundColor = BaseColor.LIGHT_GRAY;
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            companyItemTable.AddCell(cell);

            //amount
            cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.Amount", lang.Id), highLightFont));
            cell.BackgroundColor = BaseColor.LIGHT_GRAY;
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            companyItemTable.AddCell(cell);

            //rate
            cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.Rate", lang.Id), highLightFont));
            cell.BackgroundColor = BaseColor.LIGHT_GRAY;
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            companyItemTable.AddCell(cell);

            //fee
            cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductTotal", lang.Id), highLightFont));
            cell.BackgroundColor = BaseColor.LIGHT_GRAY;
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            companyItemTable.AddCell(cell);

            //First line
            //item #1
            int i = 1;
            cell = new PdfPCell(new Phrase(i.ToString(), font));
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            companyItemTable.AddCell(cell);

            //Description 1
            cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.PartnershipProfitSharingFee", lang.Id), font));
            companyItemTable.AddCell(cell);

            //Amount 1
            cell = new PdfPCell(new Phrase(_priceFormatter.FormatPrice(orderTotalWithDiscount, true, false), font));
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            companyItemTable.AddCell(cell);

            //Rate 1
            decimal commerceServiceRatePercent = store.ServiceChargeRate / 100M;
            cell = new PdfPCell(new Phrase(commerceServiceRatePercent.ToString("P", culture), font));
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            companyItemTable.AddCell(cell);

            //Fee 1
            cell = new PdfPCell(new Phrase(_priceFormatter.FormatPrice(serviceChargeFee, true, false), font));
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            companyItemTable.AddCell(cell);

            if (invoice.TransactionProcessingCharge > 0)
            {
                i++;
                //Second line
                decimal transactionProcessingCharge = invoice.TransactionProcessingCharge ?? 0;
                decimal tracksactionProcessingChargeRate = store.TransactionProcessingChargeRate ?? 0;
                if (store.TransactionProcessingChargeRate == 0)
                    tracksactionProcessingChargeRate = _invoiceSettings.TransactionProcessingChargeRate;

                //item #2
                cell = new PdfPCell(new Phrase(i.ToString(), font));
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                companyItemTable.AddCell(cell);

                //Description 2
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.RefundServiceFee", lang.Id), font));
                companyItemTable.AddCell(cell);

                //Amount 2
                cell = new PdfPCell(new Phrase(_priceFormatter.FormatPrice(refundOrdersTransactionTotal, true, false), font));
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                companyItemTable.AddCell(cell);

                //Rate 2
                tracksactionProcessingChargeRate = tracksactionProcessingChargeRate / 100M;
                cell = new PdfPCell(new Phrase((tracksactionProcessingChargeRate).ToString("P", culture), font));
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                companyItemTable.AddCell(cell);

                //Fee 2
                cell = new PdfPCell(new Phrase(_priceFormatter.FormatPrice(transactionProcessingCharge, true, false), font));
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                companyItemTable.AddCell(cell);
            }

            if (invoice.StorageCharge > 0 && invoice.StorageCharge.HasValue)
            {
                i++;
                decimal storageRate = store.StorageChargeRate ?? 0;
                if (storageRate == 0)
                    storageRate = _invoiceSettings.StorageChargeRate;

                //Third line
                //item #3
                cell = new PdfPCell(new Phrase(i.ToString(), font));
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                companyItemTable.AddCell(cell);

                //Description 3
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.StorageCost", lang.Id), font));
                companyItemTable.AddCell(cell);

                //Amount 3
                cell = new PdfPCell(new Phrase(_priceFormatter.FormatPrice(store.StorageAmount, true, false), font));
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                companyItemTable.AddCell(cell);

                //Rate 3
                decimal storageChargePercent = storageRate / 100M;
                cell = new PdfPCell(new Phrase(storageChargePercent.ToString("P", culture), font));
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                companyItemTable.AddCell(cell);

                //Fee 3
                cell = new PdfPCell(new Phrase(_priceFormatter.FormatPrice(invoice.StorageCharge.Value, true, false), font));
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                companyItemTable.AddCell(cell);
            }

            if (store.MonthlyCharge > 0)
            {
                i++;
                //Fourth line
                //item #4
                cell = new PdfPCell(new Phrase(i.ToString(), font));
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                companyItemTable.AddCell(cell);

                //Description 4
                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.OnlineSubscriptionFee", lang.Id), font));
                companyItemTable.AddCell(cell);

                //Amount 4
                cell = new PdfPCell(new Phrase(_priceFormatter.FormatPrice(store.MonthlyCharge, true, false), font));
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                companyItemTable.AddCell(cell);

                //Rate 4
                cell = new PdfPCell(new Phrase(" ", font));
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                companyItemTable.AddCell(cell);

                //Fee 4
                cell = new PdfPCell(new Phrase(_priceFormatter.FormatPrice(invoice.MonthlyCharge.Value, true, false), font));
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                companyItemTable.AddCell(cell);
            }

            doc.Add(companyItemTable);
            #endregion

            #region service fee total
            var servicCostSectionTable = new PdfPTable(2);
            servicCostSectionTable.WidthPercentage = 100f;
            servicCostSectionTable.SetWidths(new[] { 92, 8 });

            cell = new PdfPCell();
            cell.Border = Rectangle.NO_BORDER;

            //sub-total
            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.TotalFees", lang.Id), highLightFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            servicCostSectionTable.AddCell(cell);

            cell.Phrase = new Phrase(_priceFormatter.FormatPrice(invoice.SubTotal, true, false), font);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            servicCostSectionTable.AddCell(cell);

            //gst
            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.GSTTax", lang.Id), highLightFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            servicCostSectionTable.AddCell(cell);

            cell.Phrase = new Phrase(_priceFormatter.FormatPrice(invoice.Tax, true, false), font);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            servicCostSectionTable.AddCell(cell);

            //total due
            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.FeeTotal", lang.Id) + ":", highLightFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            cell.Border = Rectangle.TOP_BORDER;
            cell.PaddingTop = 3f;
            servicCostSectionTable.AddCell(cell);

            cell.Phrase = new Phrase(_priceFormatter.FormatPrice(invoice.Total, true, false), font);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            cell.Border = Rectangle.TOP_BORDER;
            servicCostSectionTable.AddCell(cell);

            doc.Add(servicCostSectionTable);
            doc.Add(new Paragraph(" "));
            #endregion

            #region Summary
            var summaryFooterTable = new PdfPTable(2);
            summaryFooterTable.WidthPercentage = 100f;
            summaryFooterTable.SetWidths(new[] { 50, 50 });

            //empty table
            var emptyTable = new PdfPTable(1);
            emptyTable.AddCell(emptyBorderlessCell);

            var emptyTableCell = new PdfPCell(emptyTable);
            emptyTableCell.Border = Rectangle.NO_BORDER;
            summaryFooterTable.AddCell(emptyTableCell);

            //summary table
            var summaryTable = new PdfPTable(2);
            summaryTable.WidthPercentage = 100f;
            summaryTable.SetWidths(new[] { 70, 30 });

            cell = new PdfPCell();
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            cell.Colspan = 2;
            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.Summary", lang.Id), titleFont);
            cell.BackgroundColor = BaseColor.LIGHT_GRAY;
            summaryTable.AddCell(cell);

            //Net transaction total
            cell.Colspan = 1;//Reset the colspan to 1
            cell.BackgroundColor = null;

            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.NetTransactionTotal", lang.Id), highLightFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            summaryTable.AddCell(cell);

            cell.Phrase = new Phrase(_priceFormatter.FormatPrice(netTransactionTotal, true, false), font);
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            summaryTable.AddCell(cell);

            //e-commerce fee
            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.FeeTotal", lang.Id), highLightFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            summaryTable.AddCell(cell);

            cell.Phrase = new Phrase(_priceFormatter.FormatPrice(invoice.Total, true, false), font);
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            summaryTable.AddCell(cell);

            //total deposit
            cell.Phrase = new Phrase(_localizationService.GetResource("PDFInvoice.TotalDeposit", lang.Id), highLightFont);
            cell.HorizontalAlignment = Element.ALIGN_RIGHT;
            summaryTable.AddCell(cell);

            cell.Phrase = new Phrase(_priceFormatter.FormatPrice(netTransactionTotal - invoice.Total, true, false), font);
            cell.HorizontalAlignment = Element.ALIGN_CENTER;
            summaryTable.AddCell(cell);

            var summaryTableCell = new PdfPCell(summaryTable);
            summaryFooterTable.AddCell(summaryTableCell);
            doc.Add(summaryFooterTable);
            #endregion

            #endregion
        }

        private static void printWayBillBorder(PdfWriter writer, Document document)
        {
            var content = writer.DirectContent;
            var pageBorderRect = new Rectangle(document.PageSize);

            pageBorderRect.Left += (document.LeftMargin / 2);
            pageBorderRect.Right -= (document.RightMargin / 2);
            pageBorderRect.Top -= (document.TopMargin / 2);
            pageBorderRect.Bottom += (document.BottomMargin / 2);

            content.SetColorStroke(BaseColor.BLACK);
            content.SetLineWidth(1f);
            content.SetLineDash(0f);
            content.Rectangle(pageBorderRect.Left, pageBorderRect.Bottom, pageBorderRect.Width, pageBorderRect.Height);
            content.Stroke();
        }

        private static void checkPackageForWaybill(LogisticsPackage package)
        {
            var shipment = package.Shipment;

            int numNonNullDimensions = 0;
            if (shipment.Width.HasValue) { numNonNullDimensions++; }
            if (shipment.Height.HasValue) { numNonNullDimensions++; }
            if (shipment.Length.HasValue) { numNonNullDimensions++; }

            if (numNonNullDimensions > 0 && numNonNullDimensions < 3)
            {
                throw new Exception(String.Format("Shipment linear dimensions only partially available for Package ID: {0}", package.Id));
            }
        }

        private static string formatAddress(Address address)
        {
            string addressStr = String.Empty;

            if (!String.IsNullOrEmpty(address.Company))
            {
                addressStr += String.Format("{0}\n", address.Company);
            }
            else
            {
                // only display first + last name if company name is empty
                addressStr += String.Format("{0} {1}\n", address.FirstName, address.LastName);
            }

            if (!String.IsNullOrEmpty(address.Address2))
            {
                addressStr += String.Format("{0}-{1}", address.Address2, address.Address1);
            }
            else
            {
                addressStr += address.Address1;
            }
            if (!String.IsNullOrEmpty(address.City))
            {
                addressStr += " " + address.City;
            }
            return addressStr;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Print an order to PDF
        /// </summary>
        /// <param name="stream">Stream</param>
        /// <param name="orders">Orders</param>
        /// <param name="lang">Language</param>
        //public virtual void PrintOrdersToPdf(Stream stream, IList<Order> orders, Language lang)
        //{
        //    if (stream == null)
        //        throw new ArgumentNullException("stream");

        //    if (orders == null)
        //        throw new ArgumentNullException("orders");

        //    if (lang == null)
        //        throw new ArgumentNullException("lang");


        //    var pageSize = PageSize.A4;

        //    if (_pdfSettings.LetterPageSizeEnabled)
        //    {
        //        pageSize = PageSize.LETTER;
        //    }


        //    var doc = new Document(pageSize);
        //    PdfWriter.GetInstance(doc, stream);
        //    doc.Open();

        //    //fonts
        //    var titleFont = GetFont();
        //    titleFont.SetStyle(Font.BOLD);
        //    titleFont.Color = BaseColor.BLACK;
        //    var font = GetFont();
        //    var attributesFont = GetFont();
        //    attributesFont.SetStyle(Font.ITALIC);

        //    int ordCount = orders.Count;
        //    int ordNum = 0;

        //    var imagePath = _webHelper.MapPath("~/content/images");
        //    var imageFile = "spotshub-textlogo-print.png";
        //    byte[] logoPicBinary;
        //    if (!File.Exists(Path.Combine(imagePath, imageFile)))
        //    {
        //        logoPicBinary = new byte[0];
        //    }
        //    else
        //    {
        //        logoPicBinary = File.ReadAllBytes(Path.Combine(imagePath, imageFile));
        //    }

        //    foreach (var order in orders)
        //    {
        //        #region Header

        //        //logo
        //        //var logoPicture = _pictureService.GetPictureById(_pdfSettings.LogoPictureId);
        //        //var logoExists = logoPicture != null;
        //        var logoExists = true;
        //        if (logoPicBinary == null || logoPicBinary.Length == 0)
        //            logoExists = false;

        //        //header
        //        var headerTable = new PdfPTable(logoExists ? 2 : 1);
        //        headerTable.WidthPercentage = 100f;
        //        if (logoExists)
        //            headerTable.SetWidths(new[] { 50, 50 });

        //        //logo
        //        if (logoExists)
        //        {
        //            //var logoFilePath = _pictureService.GetPictureLocalPath(logoPicture, 0, false);
        //            var logoFilePath = Path.Combine(imagePath, imageFile);
        //            var cellLogo = new PdfPCell(Image.GetInstance(logoFilePath));
        //            cellLogo.Border = Rectangle.NO_BORDER;
        //            headerTable.AddCell(cellLogo);
        //        }
        //        //Null header cell
        //        var cell = new PdfPCell();
        //        cell.Border = Rectangle.NO_BORDER;
        //        headerTable.AddCell(cell);
        //        doc.Add(headerTable);
        //        #endregion

        //        #region Order info
        //        //store info
        //        var orderinfoTable = new PdfPTable(2);
        //        orderinfoTable.WidthPercentage = 100f;
        //        orderinfoTable.SetWidths(new[] { 50, 50 });

        //        cell = new PdfPCell();
        //        cell.Border = Rectangle.NO_BORDER;
        //        cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Order#", lang.Id), order.Id), titleFont));

        //        cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.OrderDate", lang.Id), _dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, DateTimeKind.Utc).ToString("g", new CultureInfo(lang.LanguageCulture))), font));
        //        orderinfoTable.AddCell(cell);

        //        //Null cell
        //        cell = new PdfPCell();
        //        cell.Border = Rectangle.NO_BORDER;
        //        orderinfoTable.AddCell(cell);
        //        doc.Add(orderinfoTable);

        //        #endregion

        //        #region Addresses

        //        var addressTable = new PdfPTable(2);
        //        addressTable.WidthPercentage = 100f;
        //        addressTable.SetWidths(new[] { 50, 50 });

        //        //billing info
        //        cell = new PdfPCell();
        //        cell.Border = Rectangle.NO_BORDER;
        //        cell.AddElement(new Paragraph(_localizationService.GetResource("PDFInvoice.BillingInformation", lang.Id), titleFont));

        //        if (_addressSettings.CompanyEnabled && !String.IsNullOrEmpty(order.BillingAddress.Company))
        //            cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Company", lang.Id), order.BillingAddress.Company), font));

        //        cell.AddElement(new Paragraph(String.Format(order.BillingAddress.FirstName + " " + order.BillingAddress.LastName), font));
        //        if (_addressSettings.PhoneEnabled)
        //            cell.AddElement(new Paragraph(String.Format(order.BillingAddress.PhoneNumber + " "), font));
        //        if (_addressSettings.FaxEnabled && !String.IsNullOrEmpty(order.BillingAddress.FaxNumber))
        //            cell.AddElement(new Paragraph(String.Format(order.BillingAddress.FaxNumber + " "), font));
        //        if (_addressSettings.StreetAddressEnabled)
        //            cell.AddElement(new Paragraph(String.Format(order.BillingAddress.Address1 + " "), font));
        //        if (_addressSettings.StreetAddress2Enabled && !String.IsNullOrEmpty(order.BillingAddress.Address2))
        //            cell.AddElement(new Paragraph(String.Format(order.BillingAddress.Address2 + " "), font));
        //        if (_addressSettings.CityEnabled || _addressSettings.StateProvinceEnabled || _addressSettings.ZipPostalCodeEnabled)
        //            cell.AddElement(new Paragraph(String.Format("{0}, {1} {2}", order.BillingAddress.City, order.BillingAddress.StateProvince != null ? order.BillingAddress.StateProvince.GetLocalized(x => x.Abbreviation, lang.Id) : "", order.BillingAddress.ZipPostalCode), font));
        //        if (_addressSettings.CountryEnabled && order.BillingAddress.Country != null)
        //            cell.AddElement(new Paragraph(String.Format("{0}", order.BillingAddress.Country != null ? order.BillingAddress.Country.GetLocalized(x => x.Name, lang.Id) : ""), font));

        //        //VAT number
        //        if (!String.IsNullOrEmpty(order.VatNumber))
        //            cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.VATNumber", lang.Id), order.VatNumber), font));

        //        //payment method
        //        var paymentMethod = _paymentService.LoadPaymentMethodBySystemName(order.PaymentMethodSystemName);
        //        string paymentMethodStr = paymentMethod != null ? paymentMethod.GetLocalizedFriendlyName(_localizationService, lang.Id) : order.PaymentMethodSystemName;
        //        if (!String.IsNullOrEmpty(paymentMethodStr))
        //        {
        //            cell.AddElement(new Paragraph(" "));
        //            cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.PaymentMethod", lang.Id), paymentMethodStr), font));
        //            cell.AddElement(new Paragraph());
        //        }

        //        //purchase order number (we have to find a better to inject this information because it's related to a certain plugin)
        //        if (paymentMethod != null && paymentMethod.PluginDescriptor.SystemName.Equals("Payments.PurchaseOrder", StringComparison.InvariantCultureIgnoreCase))
        //        {
        //            cell.AddElement(new Paragraph(" "));
        //            cell.AddElement(new Paragraph("   " + String.Format(_localizationService.GetResource("PDFInvoice.PurchaseOrderNumber", lang.Id), order.PurchaseOrderNumber), font));
        //            cell.AddElement(new Paragraph());
        //        }

        //        addressTable.AddCell(cell);

        //        //shipping info
        //        if (order.ShippingStatus != ShippingStatus.ShippingNotRequired)
        //        {
        //            if (order.ShippingAddress == null)
        //                throw new NopException(string.Format("Shipping is required, but address is not available. Order ID = {0}", order.Id));
        //            cell = new PdfPCell();
        //            cell.Border = Rectangle.NO_BORDER;

        //            cell.AddElement(new Paragraph(_localizationService.GetResource("PDFInvoice.ShippingInformation", lang.Id), titleFont));
        //            if (!String.IsNullOrEmpty(order.ShippingAddress.Company))
        //                cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Company", lang.Id), order.ShippingAddress.Company), font));
        //            cell.AddElement(new Paragraph(String.Format(order.ShippingAddress.FirstName + " " + order.ShippingAddress.LastName), font));
        //            if (_addressSettings.PhoneEnabled)
        //                cell.AddElement(new Paragraph(String.Format(order.ShippingAddress.PhoneNumber + " "), font));
        //            if (_addressSettings.FaxEnabled && !String.IsNullOrEmpty(order.ShippingAddress.FaxNumber))
        //                cell.AddElement(new Paragraph(String.Format(order.ShippingAddress.FaxNumber + " "), font));
        //            if (_addressSettings.StreetAddressEnabled)
        //                cell.AddElement(new Paragraph(String.Format(order.ShippingAddress.Address1 + " "), font));
        //            if (_addressSettings.StreetAddress2Enabled && !String.IsNullOrEmpty(order.ShippingAddress.Address2))
        //                cell.AddElement(new Paragraph(String.Format(order.ShippingAddress.Address2 + " "), font));
        //            if (_addressSettings.CityEnabled || _addressSettings.StateProvinceEnabled || _addressSettings.ZipPostalCodeEnabled)
        //                cell.AddElement(new Paragraph(String.Format("{0}, {1} {2}", order.ShippingAddress.City, order.ShippingAddress.StateProvince != null ? order.ShippingAddress.StateProvince.GetLocalized(x => x.Abbreviation, lang.Id) : "", order.ShippingAddress.ZipPostalCode), font));
        //            if (_addressSettings.CountryEnabled && order.ShippingAddress.Country != null)
        //                cell.AddElement(new Paragraph(String.Format("{0}", order.ShippingAddress.Country != null ? order.ShippingAddress.Country.GetLocalized(x => x.Name, lang.Id) : ""), font));
        //            cell.AddElement(new Paragraph(" "));
        //            cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.ShippingMethod", lang.Id), order.ShippingMethod), font));
        //            cell.AddElement(new Paragraph());

        //            addressTable.AddCell(cell);
        //        }
        //        else
        //        {
        //            cell = new PdfPCell(new Phrase(" "));
        //            cell.Border = Rectangle.NO_BORDER;
        //            addressTable.AddCell(cell);
        //        }

        //        doc.Add(addressTable);
        //        doc.Add(new Paragraph(" "));

        //        #endregion

        //        #region Products
        //        //products
        //        doc.Add(new Paragraph(_localizationService.GetResource("PDFInvoice.Product(s)", lang.Id), titleFont));
        //        doc.Add(new Paragraph(" "));


        //        var orderProductVariants = _orderService.GetAllOrderProductVariants(order.Id, null, null, null, null, null, null);

        //        var productsTable = new PdfPTable(_catalogSettings.ShowProductSku ? 5 : 4);
        //        productsTable.WidthPercentage = 100f;
        //        productsTable.SetWidths(_catalogSettings.ShowProductSku ? new[] { 40, 15, 15, 15, 15 } : new[] { 40, 20, 20, 20 });

        //        //product name
        //        cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductName", lang.Id), font));
        //        cell.BackgroundColor = BaseColor.LIGHT_GRAY;
        //        cell.HorizontalAlignment = Element.ALIGN_CENTER;
        //        productsTable.AddCell(cell);

        //        //SKU
        //        if (_catalogSettings.ShowProductSku)
        //        {
        //            cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.SKU", lang.Id), font));
        //            cell.BackgroundColor = BaseColor.LIGHT_GRAY;
        //            cell.HorizontalAlignment = Element.ALIGN_CENTER;
        //            productsTable.AddCell(cell);
        //        }

        //        //price
        //        cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductPrice", lang.Id), font));
        //        cell.BackgroundColor = BaseColor.LIGHT_GRAY;
        //        cell.HorizontalAlignment = Element.ALIGN_CENTER;
        //        productsTable.AddCell(cell);

        //        //qty
        //        cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductQuantity", lang.Id), font));
        //        cell.BackgroundColor = BaseColor.LIGHT_GRAY;
        //        cell.HorizontalAlignment = Element.ALIGN_CENTER;
        //        productsTable.AddCell(cell);

        //        //total
        //        cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductTotal", lang.Id), font));
        //        cell.BackgroundColor = BaseColor.LIGHT_GRAY;
        //        cell.HorizontalAlignment = Element.ALIGN_CENTER;
        //        productsTable.AddCell(cell);

        //        for (int i = 0; i < orderProductVariants.Count; i++)
        //        {
        //            var orderProductVariant = orderProductVariants[i];
        //            var pv = orderProductVariant.ProductVariant;

        //            //product name
        //            string name = "";
        //            if (!String.IsNullOrEmpty(pv.GetLocalized(x => x.Name, lang.Id)))
        //                name = string.Format("{0} ({1})", pv.Product.GetLocalized(x => x.Name, lang.Id), pv.GetLocalized(x => x.Name, lang.Id));
        //            else
        //                name = pv.Product.GetLocalized(x => x.Name, lang.Id);
        //            cell = new PdfPCell();
        //            cell.AddElement(new Paragraph(name, font));
        //            cell.HorizontalAlignment = Element.ALIGN_LEFT;
        //            var attributesParagraph = new Paragraph(HtmlHelper.ConvertHtmlToPlainText(orderProductVariant.AttributeDescription, true, true), attributesFont);
        //            cell.AddElement(attributesParagraph);
        //            productsTable.AddCell(cell);

        //            //SKU
        //            if (_catalogSettings.ShowProductSku)
        //            {
        //                cell = new PdfPCell(new Phrase(pv.Sku ?? String.Empty, font));
        //                cell.HorizontalAlignment = Element.ALIGN_CENTER;
        //                productsTable.AddCell(cell);
        //            }

        //            //price
        //            string unitPrice = string.Empty;
        //            switch (order.CustomerTaxDisplayType)
        //            {
        //                case TaxDisplayType.ExcludingTax:
        //                    {
        //                        var opvUnitPriceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderProductVariant.UnitPriceExclTax, order.CurrencyRate);
        //                        unitPrice = _priceFormatter.FormatPrice(opvUnitPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
        //                    }
        //                    break;
        //                case TaxDisplayType.IncludingTax:
        //                    {
        //                        var opvUnitPriceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderProductVariant.UnitPriceInclTax, order.CurrencyRate);
        //                        unitPrice = _priceFormatter.FormatPrice(opvUnitPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);
        //                    }
        //                    break;
        //            }
        //            cell = new PdfPCell(new Phrase(unitPrice, font));
        //            cell.HorizontalAlignment = Element.ALIGN_LEFT;
        //            productsTable.AddCell(cell);

        //            //qty
        //            cell = new PdfPCell(new Phrase(orderProductVariant.Quantity.ToString(), font));
        //            cell.HorizontalAlignment = Element.ALIGN_LEFT;
        //            productsTable.AddCell(cell);

        //            //total
        //            string subTotal = string.Empty;
        //            switch (order.CustomerTaxDisplayType)
        //            {
        //                case TaxDisplayType.ExcludingTax:
        //                    {
        //                        var opvPriceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderProductVariant.PriceExclTax, order.CurrencyRate);
        //                        subTotal = _priceFormatter.FormatPrice(opvPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
        //                    }
        //                    break;
        //                case TaxDisplayType.IncludingTax:
        //                    {
        //                        var opvPriceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderProductVariant.PriceInclTax, order.CurrencyRate);
        //                        subTotal = _priceFormatter.FormatPrice(opvPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);
        //                    }
        //                    break;
        //            }
        //            cell = new PdfPCell(new Phrase(subTotal, font));
        //            cell.HorizontalAlignment = Element.ALIGN_LEFT;
        //            productsTable.AddCell(cell);
        //        }
        //        doc.Add(productsTable);

        //        #endregion

        //        #region Checkout attributes

        //        if (!String.IsNullOrEmpty(order.CheckoutAttributeDescription))
        //        {
        //            doc.Add(new Paragraph(" "));
        //            string attributes = HtmlHelper.ConvertHtmlToPlainText(order.CheckoutAttributeDescription, true, true);
        //            var pCheckoutAttributes = new Paragraph(attributes, font);
        //            pCheckoutAttributes.Alignment = Element.ALIGN_RIGHT;
        //            doc.Add(pCheckoutAttributes);
        //            doc.Add(new Paragraph(" "));
        //        }

        //        #endregion

        //        #region Totals

        //        //subtotal
        //        doc.Add(new Paragraph(" "));
        //        switch (order.CustomerTaxDisplayType)
        //        {
        //            case TaxDisplayType.ExcludingTax:
        //                {
        //                    var orderSubtotalExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalExclTax, order.CurrencyRate);
        //                    string orderSubtotalExclTaxStr = _priceFormatter.FormatPrice(orderSubtotalExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);

        //                    var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Sub-Total", lang.Id), orderSubtotalExclTaxStr), font);
        //                    p.Alignment = Element.ALIGN_RIGHT;
        //                    doc.Add(p);
        //                }
        //                break;
        //            case TaxDisplayType.IncludingTax:
        //                {
        //                    var orderSubtotalInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalInclTax, order.CurrencyRate);
        //                    string orderSubtotalInclTaxStr = _priceFormatter.FormatPrice(orderSubtotalInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);

        //                    var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Sub-Total", lang.Id), orderSubtotalInclTaxStr), font);
        //                    p.Alignment = Element.ALIGN_RIGHT;
        //                    doc.Add(p);
        //                }
        //                break;
        //        }
        //        //discount (applied to order subtotal)
        //        if (order.OrderSubTotalDiscountExclTax > decimal.Zero)
        //        {
        //            switch (order.CustomerTaxDisplayType)
        //            {
        //                case TaxDisplayType.ExcludingTax:
        //                    {
        //                        var orderSubTotalDiscountExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountExclTax, order.CurrencyRate);
        //                        string orderSubTotalDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderSubTotalDiscountExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);

        //                        var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Discount", lang.Id), orderSubTotalDiscountInCustomerCurrencyStr), font);
        //                        p.Alignment = Element.ALIGN_RIGHT;
        //                        doc.Add(p);
        //                    }
        //                    break;
        //                case TaxDisplayType.IncludingTax:
        //                    {
        //                        var orderSubTotalDiscountInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountInclTax, order.CurrencyRate);
        //                        string orderSubTotalDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderSubTotalDiscountInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);

        //                        var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Discount", lang.Id), orderSubTotalDiscountInCustomerCurrencyStr), font);
        //                        p.Alignment = Element.ALIGN_RIGHT;
        //                        doc.Add(p);
        //                    }
        //                    break;
        //            }
        //        }

        //        //shipping
        //        if (order.ShippingStatus != ShippingStatus.ShippingNotRequired)
        //        {
        //            switch (order.CustomerTaxDisplayType)
        //            {
        //                case TaxDisplayType.ExcludingTax:
        //                    {
        //                        var orderShippingExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderShippingExclTax, order.CurrencyRate);
        //                        string orderShippingExclTaxStr = _priceFormatter.FormatShippingPrice(orderShippingExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);

        //                        var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Shipping", lang.Id), orderShippingExclTaxStr), font);
        //                        p.Alignment = Element.ALIGN_RIGHT;
        //                        doc.Add(p);
        //                    }
        //                    break;
        //                case TaxDisplayType.IncludingTax:
        //                    {
        //                        var orderShippingInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderShippingInclTax, order.CurrencyRate);
        //                        string orderShippingInclTaxStr = _priceFormatter.FormatShippingPrice(orderShippingInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);

        //                        var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Shipping", lang.Id), orderShippingInclTaxStr), font);
        //                        p.Alignment = Element.ALIGN_RIGHT;
        //                        doc.Add(p);
        //                    }
        //                    break;
        //            }
        //        }

        //        //payment fee
        //        if (order.PaymentMethodAdditionalFeeExclTax > decimal.Zero)
        //        {
        //            switch (order.CustomerTaxDisplayType)
        //            {
        //                case TaxDisplayType.ExcludingTax:
        //                    {
        //                        var paymentMethodAdditionalFeeExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.PaymentMethodAdditionalFeeExclTax, order.CurrencyRate);
        //                        string paymentMethodAdditionalFeeExclTaxStr = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);

        //                        var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.PaymentMethodAdditionalFee", lang.Id), paymentMethodAdditionalFeeExclTaxStr), font);
        //                        p.Alignment = Element.ALIGN_RIGHT;
        //                        doc.Add(p);
        //                    }
        //                    break;
        //                case TaxDisplayType.IncludingTax:
        //                    {
        //                        var paymentMethodAdditionalFeeInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.PaymentMethodAdditionalFeeInclTax, order.CurrencyRate);
        //                        string paymentMethodAdditionalFeeInclTaxStr = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);

        //                        var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.PaymentMethodAdditionalFee", lang.Id), paymentMethodAdditionalFeeInclTaxStr), font);
        //                        p.Alignment = Element.ALIGN_RIGHT;
        //                        doc.Add(p);
        //                    }
        //                    break;
        //            }
        //        }

        //        //tax
        //        string taxStr = string.Empty;
        //        bool displayTax = true;
        //        bool displayTaxRates = true;
        //        List<TaxSurcharge> taxRates = null;
        //        if (_taxSettings.HideTaxInOrderSummary && order.CustomerTaxDisplayType == TaxDisplayType.IncludingTax)
        //        {
        //            displayTax = false;
        //        }
        //        else
        //        {
        //            if (order.OrderTax == 0 && _taxSettings.HideZeroTax)
        //            {
        //                displayTax = false;
        //                displayTaxRates = false;
        //            }
        //            else
        //            {
        //                taxRates = _taxSerivce.GetSurchargesByOrder(order).ToList().ToTaxes().ToDistinctTypes();

        //                displayTaxRates = _taxSettings.DisplayTaxRates && taxRates.Count > 0;
        //                displayTax = !displayTaxRates;

        //                var orderTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderTax, order.CurrencyRate);
        //                taxStr = _priceFormatter.FormatPrice(orderTaxInCustomerCurrency, true, order.CustomerCurrencyCode, false, lang);
        //            }
        //        }
        //        if (displayTax)
        //        {
        //            var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Tax", lang.Id), taxStr), font);
        //            p.Alignment = Element.ALIGN_RIGHT;
        //            doc.Add(p);
        //        }
        //        if (displayTaxRates && taxRates != null)
        //        {
        //            foreach (var item in taxRates)
        //            {
        //                string taxRate = String.Format(_localizationService.GetResource("PDFInvoice.TaxRate", lang.Id), _priceFormatter.FormatTaxRate(item));
        //                string taxValue = _priceFormatter.FormatPrice(_currencyService.ConvertCurrency(item.Value, order.CurrencyRate), true, order.CustomerCurrencyCode, false, lang);

        //                var p = new Paragraph(String.Format("{0} {1}", taxRate, taxValue), font);
        //                p.Alignment = Element.ALIGN_RIGHT;
        //                doc.Add(p);
        //            }
        //        }

        //        //discount (applied to order total)
        //        if (order.OrderDiscount > decimal.Zero)
        //        {
        //            var orderDiscountInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderDiscount, order.CurrencyRate);
        //            string orderDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderDiscountInCustomerCurrency, true, order.CustomerCurrencyCode, false, lang);

        //            var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Discount", lang.Id), orderDiscountInCustomerCurrencyStr), font);
        //            p.Alignment = Element.ALIGN_RIGHT;
        //            doc.Add(p);
        //        }

        //        //gift cards
        //        foreach (var gcuh in order.GiftCardUsageHistory)
        //        {
        //            string gcTitle = string.Format(_localizationService.GetResource("PDFInvoice.GiftCardInfo", lang.Id), gcuh.GiftCard.GiftCardCouponCode);
        //            string gcAmountStr = _priceFormatter.FormatPrice(-(_currencyService.ConvertCurrency(gcuh.UsedValue, order.CurrencyRate)), true, order.CustomerCurrencyCode, false, lang);

        //            var p = new Paragraph(String.Format("{0} {1}", gcTitle, gcAmountStr), font);
        //            p.Alignment = Element.ALIGN_RIGHT;
        //            doc.Add(p);
        //        }

        //        //reward points
        //        if (order.RedeemedRewardPointsEntry != null)
        //        {
        //            string rpTitle = string.Format(_localizationService.GetResource("PDFInvoice.RewardPoints", lang.Id), -order.RedeemedRewardPointsEntry.Points);
        //            string rpAmount = _priceFormatter.FormatPrice(-(_currencyService.ConvertCurrency(order.RedeemedRewardPointsEntry.UsedAmount, order.CurrencyRate)), true, order.CustomerCurrencyCode, false, lang);

        //            var p = new Paragraph(String.Format("{0} {1}", rpTitle, rpAmount), font);
        //            p.Alignment = Element.ALIGN_RIGHT;
        //            doc.Add(p);
        //        }

        //        //order total
        //        var orderTotalInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderTotal, order.CurrencyRate);
        //        string orderTotalStr = _priceFormatter.FormatPrice(orderTotalInCustomerCurrency, true, order.CustomerCurrencyCode, false, lang);


        //        var pTotal = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.OrderTotal", lang.Id), orderTotalStr), titleFont);
        //        pTotal.Alignment = Element.ALIGN_RIGHT;
        //        doc.Add(pTotal);

        //        #endregion

        //        #region Order notes

        //        if (_pdfSettings.RenderOrderNotes)
        //        {
        //            var orderNotes = order.OrderNotes
        //                .Where(on => on.DisplayToCustomer)
        //                .OrderByDescending(on => on.CreatedOnUtc)
        //                .ToList();
        //            if (orderNotes.Count > 0)
        //            {
        //                doc.Add(new Paragraph(_localizationService.GetResource("PDFInvoice.OrderNotes", lang.Id), titleFont));

        //                doc.Add(new Paragraph(" "));

        //                var notesTable = new PdfPTable(2);
        //                notesTable.WidthPercentage = 100f;
        //                notesTable.SetWidths(new[] { 30, 70 });

        //                //created on
        //                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.OrderNotes.CreatedOn", lang.Id), font));
        //                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
        //                cell.HorizontalAlignment = Element.ALIGN_CENTER;
        //                notesTable.AddCell(cell);

        //                //note
        //                cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.OrderNotes.Note", lang.Id), font));
        //                cell.BackgroundColor = BaseColor.LIGHT_GRAY;
        //                cell.HorizontalAlignment = Element.ALIGN_CENTER;
        //                notesTable.AddCell(cell);

        //                foreach (var orderNote in orderNotes)
        //                {
        //                    cell = new PdfPCell();
        //                    cell.AddElement(new Paragraph(_dateTimeHelper.ConvertToUserTime(orderNote.CreatedOnUtc, DateTimeKind.Utc).ToString(), font));
        //                    cell.HorizontalAlignment = Element.ALIGN_LEFT;
        //                    notesTable.AddCell(cell);

        //                    cell = new PdfPCell();
        //                    cell.AddElement(new Paragraph(HtmlHelper.ConvertHtmlToPlainText(orderNote.FormatOrderNoteText(), true, true), font));
        //                    cell.HorizontalAlignment = Element.ALIGN_LEFT;
        //                    notesTable.AddCell(cell);
        //                }
        //                doc.Add(notesTable);
        //            }
        //        }

        //        #endregion

        //        ordNum++;
        //        if (ordNum < ordCount)
        //        {
        //            doc.NewPage();
        //        }
        //    }
        //    doc.Close();
        //}

        public virtual void PrintOrdersToPdf(Stream stream, IList<Order> orders, Language lang)
        {

            if (stream == null)
                throw new ArgumentNullException("stream");

            if (orders == null)
                throw new ArgumentNullException("orders");

            if (lang == null)
                throw new ArgumentNullException("lang");


            var pageSize = PageSize.A4;

            if (_pdfSettings.LetterPageSizeEnabled)
            {
                pageSize = PageSize.LETTER;
            }


            var doc = new Document(pageSize);
            PdfWriter.GetInstance(doc, stream);
            doc.Open();

            //fonts
            //var titleFont = GetFont();
            //titleFont.SetStyle(Font.BOLD);
            //titleFont.Color = BaseColor.BLACK;
            //titleFont.Size = 12f;

            //var subTitleFont = GetFont();
            //subTitleFont.SetStyle(Font.BOLD);
            //subTitleFont.Size = 8f;

            //var font = GetFont();
            //font.Size = 6f;

            //var attributesFont = GetFont();
            //attributesFont.SetStyle(Font.ITALIC);

            var font = GetRobotoFont();
            var fontBold = GetRobotoBoldFont();
            font.Size = 9f;
            fontBold.Size = 9f;

            int ordCount = orders.Count;
            int ordNum = 0;

            foreach (var order in orders)
            {
                var cell = new PdfPCell();
                var paragraph = new Paragraph();

                #region Header

                var headTable = new PdfPTable(12) { WidthPercentage = 100f, HorizontalAlignment = Element.ALIGN_LEFT };

                headTable.AddCell(
                new PdfPCell(Image.GetInstance(HostingEnvironment.MapPath("~/Content/images/logo_print.png")))
                {
                    Border = Rectangle.NO_BORDER,
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    VerticalAlignment = Element.ALIGN_TOP,
                    Colspan = 4,
                    FixedHeight = 45f
                });

                fontBold.Size = 12f;
                paragraph = new Paragraph();
                paragraph.Add(new Phrase("We Deliver Happiness!", fontBold));
                paragraph.SetLeading(0, 1.3f);
                paragraph.Font = font;
                paragraph.Alignment = Element.ALIGN_CENTER;
                cell = new PdfPCell()
                {
                    Border = Rectangle.NO_BORDER,
                    HorizontalAlignment = Element.ALIGN_CENTER,
                    VerticalAlignment = Element.ALIGN_MIDDLE,
                    Colspan = 4
                };
                cell.AddElement(paragraph);
                headTable.AddCell(cell);
                fontBold.Size = 9f;

                paragraph = new Paragraph();
                paragraph.Font = font;
                paragraph.SetLeading(0, 1.3f);
                paragraph.Alignment = Element.ALIGN_RIGHT;
                paragraph.Add("Order: #" + order.Id + "\n");
                paragraph.Add("Client #: " + order.CustomerId + "\n");
                paragraph.Add("Date: " + order.CreatedOnUtc.ToString("dd/MM/yyyy"));

                cell = new PdfPCell()
                {
                    Border = Rectangle.NO_BORDER,
                    HorizontalAlignment = Element.ALIGN_RIGHT,
                    VerticalAlignment = Element.ALIGN_TOP,
                    Colspan = 4
                };
                cell.AddElement(paragraph);
                headTable.AddCell(cell);

                doc.Add(headTable);

                #endregion

                #region Addresses

                //shipping info
                if (order.ShippingStatus != ShippingStatus.ShippingNotRequired)
                {
                    var addressTable = new PdfPTable(12) { WidthPercentage = 100f };
                    addressTable.SpacingBefore = 15f;
                    if (order.ShippingAddress == null)
                        throw new NopException(string.Format("Shipping is required, but address is not available. Order ID = {0}", order.Id));


                    font.Size = 9f;
                    cell = new PdfPCell { Border = Rectangle.NO_BORDER };

                    cell.AddElement(new Paragraph("Ship To:", fontBold));
                    if (!String.IsNullOrEmpty(order.ShippingAddress.Company))
                        cell.AddElement(new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Company", lang.Id), order.ShippingAddress.Company), font));
                    cell.AddElement(new Paragraph(String.Format(order.ShippingAddress.FirstName + " " + order.ShippingAddress.LastName + "\n"), font));

                    if (_addressSettings.StreetAddress2Enabled && !String.IsNullOrEmpty(order.ShippingAddress.Address2))
                        cell.AddElement(new Paragraph(String.Format(order.ShippingAddress.Address2 + " "), font));

                    if (_addressSettings.StreetAddressEnabled)
                        cell.AddElement(new Paragraph(String.Format(order.ShippingAddress.Address1 + "\n"), font));

                    if (_addressSettings.CityEnabled || _addressSettings.StateProvinceEnabled || _addressSettings.ZipPostalCodeEnabled)
                        cell.AddElement(new Paragraph(String.Format("{0}, {1} {2}", order.ShippingAddress.City, order.ShippingAddress.StateProvince != null ? order.ShippingAddress.StateProvince.GetLocalized(x => x.Abbreviation, lang.Id) : "", order.ShippingAddress.ZipPostalCode), font));

                    cell.AddElement(new Phrase(Chunk.NEWLINE));
                    font.Size = 7.5f;
                    cell.AddElement(new Phrase("Shipped via SpotsHUB EXPRESS Courier Service", font));

                    cell.Colspan = 6;

                    addressTable.AddCell(cell);


                    font.Size = 9f;
                    cell = new PdfPCell { Border = Rectangle.NO_BORDER };

                    cell.AddElement(new Paragraph("Bill To:", fontBold));

                    if (_addressSettings.CompanyEnabled && !String.IsNullOrEmpty(order.BillingAddress.Company))
                        cell.AddElement(new Paragraph(String.Format("Company:", order.BillingAddress.Company), font));

                    cell.AddElement(new Paragraph(String.Format(order.BillingAddress.FirstName + " " + order.BillingAddress.LastName), font));

                    if (_addressSettings.StreetAddressEnabled)
                        cell.AddElement(new Paragraph(String.Format(order.BillingAddress.Address1 + " "), font));
                    if (_addressSettings.StreetAddress2Enabled && !String.IsNullOrEmpty(order.BillingAddress.Address2))
                        cell.AddElement(new Paragraph(String.Format(order.BillingAddress.Address2 + " "), font));
                    if (_addressSettings.CityEnabled || _addressSettings.StateProvinceEnabled || _addressSettings.ZipPostalCodeEnabled)
                        cell.AddElement(new Paragraph(String.Format("{0}, {1} {2}", order.BillingAddress.City, order.BillingAddress.StateProvince != null ? order.BillingAddress.StateProvince.GetLocalized(x => x.Abbreviation, lang.Id) : "", order.BillingAddress.ZipPostalCode), font));
                    if (_addressSettings.CountryEnabled && order.BillingAddress.Country != null)
                        cell.AddElement(new Paragraph(String.Format("{0}", order.BillingAddress.Country != null ? order.BillingAddress.Country.GetLocalized(x => x.Name, lang.Id) : ""), font));

                    cell.Colspan = 6;

                    addressTable.AddCell(cell);

                    doc.Add(addressTable);
                }

                #endregion

                #region Products

                var productTable = new PdfPTable(12) { WidthPercentage = 100f };

                productTable.AddCell(new PdfPCell()
                {
                    Colspan = 12,
                    Phrase = new Phrase(Chunk.NEWLINE),
                    Border = Rectangle.NO_BORDER
                });

                var orderProductVariants = _orderService.GetAllOrderProductVariants(order.Id, null, null, null, null, null, null);

                cell = new PdfPCell(new Phrase("Product", fontBold))
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Colspan = 5
                };
                productTable.AddCell(cell);

                //item number
                productTable.AddCell(new PdfPCell(new Phrase("Item Number", fontBold))
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Colspan = 2
                });

                //price
                productTable.AddCell(new PdfPCell(new Phrase("Price", fontBold))
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Colspan = 2
                });

                //qty
                productTable.AddCell(new PdfPCell(new Phrase("Qty", fontBold))
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Colspan = 1
                });

                //total
                productTable.AddCell(new PdfPCell(new Phrase("Total", fontBold))
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Colspan = 2
                });


                for (var i = 0; i < orderProductVariants.Count; i++)
                {
                    var orderProductVariant = orderProductVariants[i];
                    var pv = orderProductVariant.ProductVariant;

                    //product name
                    cell = new PdfPCell(new Paragraph(pv.FullProductName, font));
                    cell.Colspan = 5;
                    productTable.AddCell(cell);

                    //item number
                    cell = new PdfPCell(new Phrase(pv.Gtin, font));
                    cell.Colspan = 2;
                    productTable.AddCell(cell);

                    //price
                    string unitPrice = string.Empty;
                    switch (order.CustomerTaxDisplayType)
                    {
                        case TaxDisplayType.ExcludingTax:
                            {
                                var opvUnitPriceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderProductVariant.UnitPriceExclTax, order.CurrencyRate);
                                unitPrice = _priceFormatter.FormatPrice(opvUnitPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                            }
                            break;
                        case TaxDisplayType.IncludingTax:
                            {
                                var opvUnitPriceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderProductVariant.UnitPriceInclTax, order.CurrencyRate);
                                unitPrice = _priceFormatter.FormatPrice(opvUnitPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);
                            }
                            break;
                    }
                    cell = new PdfPCell(new Phrase(unitPrice, font)) { HorizontalAlignment = Element.ALIGN_LEFT };
                    cell.Colspan = 2;
                    productTable.AddCell(cell);

                    //qty
                    cell = new PdfPCell(new Phrase(orderProductVariant.Quantity.ToString(), font));
                    cell.Colspan = 1;
                    productTable.AddCell(cell);

                    //total
                    string subTotal = string.Empty;
                    switch (order.CustomerTaxDisplayType)
                    {
                        case TaxDisplayType.ExcludingTax:
                            {
                                var opvPriceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderProductVariant.PriceExclTax, order.CurrencyRate);
                                subTotal = _priceFormatter.FormatPrice(opvPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                            }
                            break;
                        case TaxDisplayType.IncludingTax:
                            {
                                var opvPriceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderProductVariant.PriceInclTax, order.CurrencyRate);
                                subTotal = _priceFormatter.FormatPrice(opvPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);
                            }
                            break;
                    }
                    cell = new PdfPCell(new Phrase(subTotal, font)) { HorizontalAlignment = Element.ALIGN_LEFT };
                    cell.Colspan = 2;
                    productTable.AddCell(cell);

                }
                doc.Add(productTable);

                #endregion

                #region subtotal

                var totalTable = new PdfPTable(12) { WidthPercentage = 100f };

                totalTable.AddCell(new PdfPCell
                {
                    Colspan = 9,
                    Border = Rectangle.NO_BORDER
                });

                totalTable.AddCell(new PdfPCell
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Phrase = new Phrase("Subtotal", fontBold),
                    Border = Rectangle.NO_BORDER,
                    Colspan = 1
                });

                switch (order.CustomerTaxDisplayType)
                {
                    case TaxDisplayType.ExcludingTax:
                        {
                            var orderSubtotalExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalExclTax, order.CurrencyRate);
                            var orderSubtotalExclTaxStr = _priceFormatter.FormatPrice(orderSubtotalExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);

                            totalTable.AddCell(new PdfPCell
                            {
                                HorizontalAlignment = Element.ALIGN_RIGHT,
                                Phrase = new Phrase(orderSubtotalExclTaxStr, font),
                                Border = Rectangle.NO_BORDER,
                                Colspan = 2
                            });
                        }
                        break;
                    case TaxDisplayType.IncludingTax:
                        {
                            var orderSubtotalInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalInclTax, order.CurrencyRate);
                            string orderSubtotalInclTaxStr = _priceFormatter.FormatPrice(orderSubtotalInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);

                            totalTable.AddCell(new PdfPCell
                            {
                                HorizontalAlignment = Element.ALIGN_RIGHT,
                                Phrase = new Phrase(orderSubtotalInclTaxStr, font),
                                Border = Rectangle.NO_BORDER,
                                Colspan = 2
                            });
                        }
                        break;
                }

                //discount (applied to order subtotal)
                if (order.OrderSubTotalDiscountExclTax > decimal.Zero)
                {
                    totalTable.AddCell(new PdfPCell
                    {
                        Colspan = 9,
                        Border = Rectangle.NO_BORDER
                    });
                    totalTable.AddCell(new PdfPCell
                    {
                        HorizontalAlignment = Element.ALIGN_LEFT,
                        Phrase = new Phrase("Discount", fontBold),
                        Border = Rectangle.NO_BORDER,
                        Colspan = 1
                    });
                    switch (order.CustomerTaxDisplayType)
                    {
                        case TaxDisplayType.ExcludingTax:
                            {
                                var orderSubTotalDiscountExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountExclTax, order.CurrencyRate);
                                string orderSubTotalDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderSubTotalDiscountExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);

                                totalTable.AddCell(new PdfPCell
                                {
                                    HorizontalAlignment = Element.ALIGN_RIGHT,
                                    Phrase = new Phrase(orderSubTotalDiscountInCustomerCurrencyStr, font),
                                    Border = Rectangle.NO_BORDER,
                                    Colspan = 2
                                });
                            }
                            break;
                        case TaxDisplayType.IncludingTax:
                            {
                                var orderSubTotalDiscountInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountInclTax, order.CurrencyRate);
                                string orderSubTotalDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderSubTotalDiscountInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);

                                totalTable.AddCell(new PdfPCell
                                {
                                    HorizontalAlignment = Element.ALIGN_RIGHT,
                                    Phrase = new Phrase(orderSubTotalDiscountInCustomerCurrencyStr, font),
                                    Border = Rectangle.NO_BORDER,
                                    Colspan = 2
                                });
                            }
                            break;
                    }
                }

                //shipping
                if (order.ShippingStatus != ShippingStatus.ShippingNotRequired && order.OrderShippingInclTax != decimal.Zero)
                {
                    totalTable.AddCell(new PdfPCell
                    {
                        Colspan = 9,
                        Border = Rectangle.NO_BORDER
                    });
                    totalTable.AddCell(new PdfPCell
                    {
                        HorizontalAlignment = Element.ALIGN_LEFT,
                        Phrase = new Phrase("Shipping", fontBold),
                        Border = Rectangle.NO_BORDER,
                        Colspan = 1
                    });
                    var shippingResult = string.Empty;
                    switch (order.CustomerTaxDisplayType)
                    {
                        case TaxDisplayType.ExcludingTax:
                            {
                                var orderShippingExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderShippingExclTax, order.CurrencyRate);
                                shippingResult = _priceFormatter.FormatShippingPrice(orderShippingExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false);
                            }
                            break;
                        case TaxDisplayType.IncludingTax:
                            {
                                var orderShippingInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderShippingInclTax, order.CurrencyRate);
                                shippingResult = _priceFormatter.FormatShippingPrice(orderShippingInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true);
                            }
                            break;
                    }

                    totalTable.AddCell(new PdfPCell
                    {
                        HorizontalAlignment = Element.ALIGN_RIGHT,
                        Phrase = new Phrase(shippingResult, font),
                        Border = Rectangle.NO_BORDER,
                        Colspan = 2
                    });
                }

                // Tax
                List<TaxSurcharge> taxRates = _taxSerivce.GetSurchargesByOrder(order).ToList().ToTaxes().ToDistinctTypes();

                if (taxRates != null)
                {
                    foreach (var item in taxRates)
                    {
                        string taxValue = _priceFormatter.FormatPrice(_currencyService.ConvertCurrency(item.Value, order.CurrencyRate), true, order.CustomerCurrencyCode, false, lang);

                        totalTable.AddCell(new PdfPCell
                        {
                            Colspan = 9,
                            Border = Rectangle.NO_BORDER
                        });

                        if (item.SurchargeTypeId == 1)
                        {
                            totalTable.AddCell(new PdfPCell
                            {
                                HorizontalAlignment = Element.ALIGN_LEFT,
                                Phrase = new Phrase("GST", fontBold),
                                Colspan = 1,
                                Border = Rectangle.NO_BORDER
                            });

                        }
                        else if (item.SurchargeTypeId == 2)
                        {
                            totalTable.AddCell(new PdfPCell
                            {
                                HorizontalAlignment = Element.ALIGN_LEFT,
                                Phrase = new Phrase("PST", fontBold),
                                Colspan = 1,
                                Border = Rectangle.NO_BORDER
                            });

                        }

                        totalTable.AddCell(new PdfPCell
                        {
                            HorizontalAlignment = Element.ALIGN_RIGHT,
                            Phrase = new Phrase(taxValue, font),
                            Colspan = 2,
                            Border = Rectangle.NO_BORDER
                        });
                    }
                }


                totalTable.AddCell(new PdfPCell
                {
                    Colspan = 9,
                    Border = Rectangle.NO_BORDER
                });

                totalTable.AddCell(new PdfPCell
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Phrase = new Phrase("Total", fontBold),
                    Colspan = 1,
                    Border = Rectangle.NO_BORDER
                });

                var orderTotalInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderTotal, order.CurrencyRate);
                string orderTotalStr = _priceFormatter.FormatPrice(orderTotalInCustomerCurrency, true, order.CustomerCurrencyCode, false, lang);

                totalTable.AddCell(new PdfPCell
                {
                    HorizontalAlignment = Element.ALIGN_RIGHT,
                    Phrase = new Phrase(orderTotalStr, fontBold),
                    Colspan = 2,
                    Border = Rectangle.NO_BORDER
                });

                totalTable.AddCell(new PdfPCell()
                {
                    Colspan = 12,
                    Border = Rectangle.NO_BORDER,
                    BorderColorBottom = BaseColor.BLACK,
                    BorderWidthBottom = 0.25f,
                    FixedHeight = 5f
                });

                totalTable.SpacingBefore = 5f;

                doc.Add(totalTable);
                #endregion


                #region explain

                var explainTable = new PdfPTable(12) { WidthPercentage = 100f };

                //explain
                var explain = new StringBuilder();
                explain.AppendLine("Return policy:");
                explain.AppendLine("• SpotsHUB accept return for most products within 30 days of delivery.");
                explain.AppendLine("• Some products have different policies or requirements associated with them.");
                explain.AppendLine("• Food products are not returnable.");
                explain.AppendLine("• For health and hygiene reasons, some products cannot be return after delivery.");
                explain.AppendLine("• Full refund only applies to return products that meet one of the following conditions:");
                explain.AppendLine("- Return product must be brand new, and the packaging must never been opened and be in resalable condition.");
                explain.AppendLine("- Product is returned due to a SpotsHUB error (e.g., wrong product was sent). SpotsHUB will cover the full return shipping costs.");
                explain.AppendLine("- Product received is damaged or defective. Refund will be issued once the return request is approved by SpotsHUB.");
                explain.AppendLine("• Final sale products are not eligible for return or exchange.");
                explain.AppendLine("• A 40% restocking fee will apply to return products with one of the following return reasons and buyers will be responsible for the full return shipping costs:");
                explain.AppendLine("- Buyers have changed their mind about a purchase and return the product in its original condition within the allowable return window.");
                explain.AppendLine("- Buyers have returned a product in its original condition but passed the deadline of return for more than 15 days. Buyers are given the 15 days from the deadline to return the product to SpotsHUB.");
                explain.AppendLine("- Buyers have refused to accept the delivery of the product. ");
                explain.AppendLine("- Buyers have returned a product with missing parts, not in its original condition, with obvious signs of usage, and because of any other reasons that is not due to a SpostHUB error.");
                explain.AppendLine("• No return and refund will be approved for products damaged due to faulty usage or installation by buyers.");
                explain.AppendLine("• Return and refund requests may only be initiated from the original accounts of order placement.");
                explain.AppendLine("");
                explain.AppendLine("");
                explain.AppendLine("SpotsHUB Customer Service Team");
                explain.AppendLine("Phone:604-298-9888");
                explain.AppendLine("Email:info@spotshub.com");
                font.Size = 7.5f;
                cell = new PdfPCell
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Border = Rectangle.NO_BORDER,
                    Colspan = 12
                };
                paragraph = new Paragraph(new Phrase(explain.ToString(), font));
                paragraph.SetLeading(0, 1.3f);
                cell.AddElement(paragraph);
                explainTable.AddCell(cell);
                explainTable.SpacingBefore = 15f;

                doc.Add(explainTable);

                #endregion


                ordNum++;
                if (ordNum < ordCount)
                {
                    doc.NewPage();
                }
            }
            doc.Close();
        }

        /// <summary>
        /// Print an invoice into PDF
        /// </summary>
        /// <param name="stream">Stream</param>
        /// <param name="invoice">Invoice</param>
        /// <param name="lang">Language</param>
        /// <param name="useCustomerTimeZone">Use cutomer time zone info. true to use customer info instead of invoice time zone</param>
        public virtual void PrintInvoiceToPdf(Stream stream, Invoice invoice, Language lang, bool useCustomerTimeZone = false)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            if (invoice == null)
                throw new ArgumentNullException("invoice");

            if (lang == null)
                throw new ArgumentNullException("lang");

            var pageMarginLRSides = 0.5f * PIXELS_PER_INCH;
            var pageMarginTBSides = 0.2f * PIXELS_PER_INCH;
            var pageSize = PageSize.A4_LANDSCAPE.Rotate();

            var doc = new Document(pageSize, pageMarginLRSides, pageMarginLRSides, pageMarginTBSides, pageMarginTBSides);
            PdfWriter.GetInstance(doc, stream);
            doc.Open();

            populateInvoiceAsPdf(doc, invoice, lang, useCustomerTimeZone);
            doc.Close();
        }

        /// <summary>
        /// Print a list of invoices to PDF
        /// </summary>
        /// <param name="stream">Stream</param>
        /// <param name="invoices">Invoices</param>
        /// <param name="lang">Language</param>
        /// <param name="useCustomerTimeZone">Use cutomer time zone info. true to use customer info instead of invoice time zone</param>
        public virtual void PrintInvoiceToPdf(Stream stream, IList<Invoice> invoices, Language lang, bool useCustomerTimeZone = false)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            if (invoices == null)
                throw new ArgumentNullException("invoices");

            if (lang == null)
                throw new ArgumentNullException("lang");

            if (invoices.Count == 0)
                throw new ArgumentException("Parameter invoices must be a list of at least one element");

            // define label page size
            var pageMarginLRSides = 0.5f * PIXELS_PER_INCH;
            var pageMarginTBSides = 0.2f * PIXELS_PER_INCH;
            var pageSize = PageSize.A4_LANDSCAPE.Rotate();

            var doc = new Document(pageSize, pageMarginLRSides, pageMarginLRSides, pageMarginTBSides, pageMarginTBSides);
            PdfWriter.GetInstance(doc, stream);
            doc.Open();

            populateInvoiceAsPdf(doc, invoices[0], lang, useCustomerTimeZone);

            for (int idx = 1; idx < invoices.Count; idx++)
            {
                var invoice = invoices[idx];

                doc.NewPage();
                populateInvoiceAsPdf(doc, invoice, lang, useCustomerTimeZone);
            }

            doc.Close();
        }

        /// <summary>
        /// Print packaging slips to PDF
        /// </summary>
        /// <param name="stream">Stream</param>
        /// <param name="shipments">Shipments</param>
        /// <param name="lang">Language</param>
        public virtual void PrintPackagingSlipsToPdf(Stream stream, IList<Shipment> shipments, Language lang)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            if (shipments == null)
                throw new ArgumentNullException("shipments");

            var pageSize = PageSize.A4;

            if (_pdfSettings.LetterPageSizeEnabled)
            {
                pageSize = PageSize.LETTER;
            }

            var doc = new Document(pageSize);
            PdfWriter.GetInstance(doc, stream);
            doc.Open();

            //fonts
            var titleFont = GetFont();
            titleFont.SetStyle(Font.BOLD);
            titleFont.Color = BaseColor.BLACK;
            var font = GetFont();
            var attributesFont = GetFont();
            attributesFont.SetStyle(Font.ITALIC);

            int shipmentCount = shipments.Count;
            int shipmentNum = 0;

            foreach (var shipment in shipments)
            {
                var order = shipment.Order;
                if (order.ShippingAddress != null)
                {
                    doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Shipment", lang.Id), shipment.Id), titleFont));
                    doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Order", lang.Id), order.Id), titleFont));

                    if (_addressSettings.CompanyEnabled && !String.IsNullOrEmpty(order.ShippingAddress.Company))
                        doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Company", lang.Id), order.ShippingAddress.Company), font));

                    doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Name", lang.Id), order.ShippingAddress.FirstName + " " + order.ShippingAddress.LastName), font));
                    if (_addressSettings.PhoneEnabled)
                        doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Phone", lang.Id), order.ShippingAddress.PhoneNumber), font));
                    if (_addressSettings.StreetAddressEnabled)
                        doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Address", lang.Id), order.ShippingAddress.Address1), font));

                    if (_addressSettings.StreetAddress2Enabled && !String.IsNullOrEmpty(order.ShippingAddress.Address2))
                        doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Address2", lang.Id), order.ShippingAddress.Address2), font));

                    if (_addressSettings.CityEnabled || _addressSettings.StateProvinceEnabled || _addressSettings.ZipPostalCodeEnabled)
                        doc.Add(new Paragraph(String.Format("{0}, {1} {2}", order.ShippingAddress.City, order.ShippingAddress.StateProvince != null ? order.ShippingAddress.StateProvince.GetLocalized(x => x.Name, lang.Id) : "", order.ShippingAddress.ZipPostalCode), font));

                    if (_addressSettings.CountryEnabled && order.ShippingAddress.Country != null)
                        doc.Add(new Paragraph(String.Format("{0}", order.ShippingAddress.Country != null ? order.ShippingAddress.Country.GetLocalized(x => x.Name, lang.Id) : ""), font));

                    doc.Add(new Paragraph(" "));

                    doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.ShippingMethod", lang.Id), order.ShippingMethod), font));
                    doc.Add(new Paragraph(" "));

                    var productsTable = new PdfPTable(3);
                    productsTable.WidthPercentage = 100f;
                    productsTable.SetWidths(new[] { 60, 20, 20 });

                    //product name
                    var cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFPackagingSlip.ProductName", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    productsTable.AddCell(cell);

                    //SKU
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFPackagingSlip.SKU", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    productsTable.AddCell(cell);

                    //qty
                    cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFPackagingSlip.QTY", lang.Id), font));
                    cell.BackgroundColor = BaseColor.LIGHT_GRAY;
                    cell.HorizontalAlignment = Element.ALIGN_CENTER;
                    productsTable.AddCell(cell);

                    foreach (var sopv in shipment.ShipmentOrderProductVariants)
                    {
                        //product name
                        var opv = _orderService.GetOrderProductVariantById(sopv.OrderProductVariantId);
                        if (opv == null)
                            continue;

                        var pv = opv.ProductVariant;
                        string name = "";
                        if (!String.IsNullOrEmpty(pv.GetLocalized(x => x.Name, lang.Id)))
                            name = string.Format("{0} ({1})", pv.Product.GetLocalized(x => x.Name, lang.Id), pv.GetLocalized(x => x.Name, lang.Id));
                        else
                            name = pv.Product.GetLocalized(x => x.Name, lang.Id);
                        cell = new PdfPCell();
                        cell.AddElement(new Paragraph(name, font));
                        cell.HorizontalAlignment = Element.ALIGN_LEFT;
                        //20. E-commerce shipment, on the shipping label, it should not show "Letter Size Package", it should be blank. Screen shot provided.
                        //opv.AttributeDescription = "";
                        var attributesParagraph = new Paragraph(HtmlHelper.ConvertHtmlToPlainText(opv.AttributeDescription, true, true), attributesFont);
                        cell.AddElement(attributesParagraph);
                        productsTable.AddCell(cell);

                        //SKU
                        cell = new PdfPCell(new Phrase(pv.Sku ?? String.Empty, font));
                        cell.HorizontalAlignment = Element.ALIGN_CENTER;
                        productsTable.AddCell(cell);

                        //qty
                        cell = new PdfPCell(new Phrase(sopv.Quantity.ToString(), font));
                        cell.HorizontalAlignment = Element.ALIGN_CENTER;
                        productsTable.AddCell(cell);
                    }
                    doc.Add(productsTable);
                }

                shipmentNum++;
                if (shipmentNum < shipmentCount)
                {
                    doc.NewPage();
                }
            }


            doc.Close();
        }

        /// <summary>
        /// Print product collection to PDF
        /// </summary>
        /// <param name="stream">Stream</param>
        /// <param name="products">Products</param>
        /// <param name="regionId">region Id</param>
        /// <param name="lang">Language</param>
        public virtual void PrintProductsToPdf(Stream stream, IList<Product> products, int regionId, Language lang)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            if (products == null)
                throw new ArgumentNullException("products");

            if (lang == null)
                throw new ArgumentNullException("lang");

            var pageSize = PageSize.A4;

            if (_pdfSettings.LetterPageSizeEnabled)
            {
                pageSize = PageSize.LETTER;
            }

            var doc = new Document(pageSize);
            PdfWriter.GetInstance(doc, stream);
            doc.Open();

            //fonts
            var titleFont = GetFont();
            titleFont.SetStyle(Font.BOLD);
            titleFont.Color = BaseColor.BLACK;
            var font = GetFont();

            int productNumber = 1;
            int prodCount = products.Count;

            foreach (var product in products)
            {
                string productName = product.GetLocalized(x => x.Name, lang.Id);
                string productFullDescription = product.GetLocalized(x => x.FullDescription, lang.Id);

                doc.Add(new Paragraph(String.Format("{0}. {1}", productNumber, productName), titleFont));
                doc.Add(new Paragraph(" "));
                doc.Add(new Paragraph(HtmlHelper.StripTags(HtmlHelper.ConvertHtmlToPlainText(productFullDescription)), font));
                doc.Add(new Paragraph(" "));

                var pictures = _pictureService.GetPicturesByProductId(product.Id);
                if (pictures.Count > 0)
                {
                    var table = new PdfPTable(2);
                    table.WidthPercentage = 100f;

                    for (int i = 0; i < pictures.Count; i++)
                    {
                        var pic = pictures[i];
                        if (pic != null)
                        {
                            var picBinary = _pictureService.LoadPictureBinary(pic);
                            if (picBinary != null && picBinary.Length > 0)
                            {
                                var pictureLocalPath = _pictureService.GetPictureLocalPath(pic, 200, false);
                                var cell = new PdfPCell(Image.GetInstance(pictureLocalPath));
                                cell.HorizontalAlignment = Element.ALIGN_LEFT;
                                cell.Border = Rectangle.NO_BORDER;
                                table.AddCell(cell);
                            }
                        }
                    }

                    if (pictures.Count % 2 > 0)
                    {
                        var cell = new PdfPCell(new Phrase(" "));
                        cell.Border = Rectangle.NO_BORDER;
                        table.AddCell(cell);
                    }

                    doc.Add(table);
                    doc.Add(new Paragraph(" "));
                }

                int pvNum = 1;

                foreach (var productVariant in _productService.GetProductVariantsByProductId(product.Id, regionId, true))
                {
                    string pvName = String.IsNullOrEmpty(productVariant.GetLocalized(x => x.Name, lang.Id)) ? _localizationService.GetResource("PDFProductCatalog.UnnamedProductVariant", lang.Id) : productVariant.GetLocalized(x => x.Name, lang.Id);

                    doc.Add(new Paragraph(String.Format("{0}.{1}. {2}", productNumber, pvNum, pvName), font));
                    doc.Add(new Paragraph(" "));

                    string productVariantDescription = productVariant.GetLocalized(x => x.Description, lang.Id);
                    if (!String.IsNullOrEmpty(productVariantDescription))
                    {
                        doc.Add(new Paragraph(HtmlHelper.StripTags(HtmlHelper.ConvertHtmlToPlainText(productVariantDescription)), font));
                        doc.Add(new Paragraph(" "));
                    }

                    var pic = _pictureService.GetPictureById(productVariant.PictureId);
                    if (pic != null)
                    {
                        var picBinary = _pictureService.LoadPictureBinary(pic);
                        if (picBinary != null && picBinary.Length > 0)
                        {
                            var pictureLocalPath = _pictureService.GetPictureLocalPath(pic, 200, false);
                            doc.Add(Image.GetInstance(pictureLocalPath));
                        }
                    }

                    doc.Add(new Paragraph(String.Format("{0}: {1} {2}", _localizationService.GetResource("PDFProductCatalog.Price", lang.Id), productVariant.Price.ToString("0.00"), _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode), font));
                    doc.Add(new Paragraph(String.Format("{0}: {1}", _localizationService.GetResource("PDFProductCatalog.SKU", lang.Id), productVariant.Sku), font));

                    if (productVariant.IsShipEnabled && productVariant.Weight > Decimal.Zero)
                        doc.Add(new Paragraph(String.Format("{0}: {1} {2}", _localizationService.GetResource("PDFProductCatalog.Weight", lang.Id), productVariant.Weight.ToString("0.00"), _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).Name), font));

                    if (productVariant.ManageInventoryMethod == ManageInventoryMethod.ManageStock)
                        doc.Add(new Paragraph(String.Format("{0}: {1}", _localizationService.GetResource("PDFProductCatalog.StockQuantity", lang.Id), productVariant.StockQuantity), font));

                    doc.Add(new Paragraph(" "));

                    pvNum++;
                }

                productNumber++;

                if (productNumber <= prodCount)
                {
                    doc.NewPage();
                }
            }

            doc.Close();
        }

        /// <summary>
        /// Print logistics locations to PDF
        /// </summary>
        /// <param name="stream">Stream</param>
        /// <param name="locations">Logistics locations</param>
        /// <param name="trackingUrls">List of Package tracking urls corresponding to Logistcs locations</param>
        /// <param name="plannedRouteUrl">Url corresponding to the Planned Route List</param>
        /// <param name="lang">Language</param>
        public virtual void PrintLogistcsLocationsToPdf(Stream stream, IList<LogisticsLocation> locations, IList<string> trackingUrls,
                                                        string plannedRouteUrl, Language lang)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            if (locations == null)
                throw new ArgumentNullException("locations");

            if (lang == null)
                throw new ArgumentNullException("lang");

            var pageSize = PageSize.A4_LANDSCAPE.Rotate();
            var pixelsPerInch = 72f;
            var pageMarginInInch = 0.2f;
            var pageMarginSize = pageMarginInInch * pixelsPerInch;

            var doc = new Document(pageSize, pageMarginSize, pageMarginSize, pageMarginSize, pageMarginSize);
            PdfWriter.GetInstance(doc, stream);
            doc.Open();

            //fonts
            var titleFont = GetFont();
            titleFont.SetStyle(Font.BOLD);
            titleFont.Color = BaseColor.BLACK;
            titleFont.Size = 12f;
            var columnTitleFont = GetFont();
            columnTitleFont.SetStyle(Font.BOLD);
            columnTitleFont.Size--;
            var font = GetFont();
            font.Size--;

            int locCount = locations.Count;

            if (locCount < 1)
            {
                doc.Close();
                return;
            }

            var sb = new System.Text.StringBuilder();

            var headerTable = new PdfPTable(2);
            headerTable.HorizontalAlignment = Element.ALIGN_LEFT;
            headerTable.WidthPercentage = 100f;
            headerTable.SetWidths(new int[] { 70, 30 });

            var headerCell = new PdfPCell(new Phrase(String.Format("Plan ID = {0}. Courier (ID) = {1} ({2})\n",
                                                                   locations[0].PlanId,
                                                                   locations[0].Courier.Customer.Email,
                                                                   locations[0].CourierId),
                                                     titleFont));
            headerCell.Border = Rectangle.NO_BORDER;
            headerCell.HorizontalAlignment = Element.ALIGN_LEFT;
            headerTable.AddCell(headerCell);

            if (_qrCodeSettings.Enabled && plannedRouteUrl != null)
            {
                if (!String.IsNullOrEmpty(plannedRouteUrl))
                {
                    Image plannedRouteQrCodeImg = new BarcodeQRCode(plannedRouteUrl, 20, 20, null).GetImage();
                    var cellQr = new PdfPCell(plannedRouteQrCodeImg);
                    cellQr.Border = Rectangle.NO_BORDER;
                    cellQr.HorizontalAlignment = Element.ALIGN_RIGHT;
                    cellQr.VerticalAlignment = Element.ALIGN_TOP;
                    cellQr.Rowspan = 2;
                    headerTable.AddCell(cellQr);
                }
                else
                {
                    headerCell.Phrase = new Phrase(" ", font);
                    headerCell.Rowspan = 2;
                    headerTable.AddCell(headerCell);
                }
            }

            headerCell.Rowspan = 1; // reset back to 1

            headerCell.Phrase = new Phrase(String.Format("Driver Signature: {0}  Manager Signature: {1}\n",
                                                         "___________________", "___________________"),
                                           titleFont);
            headerCell.PaddingTop = 12.0f;
            headerCell.PaddingBottom = 12.0f;
            headerTable.AddCell(headerCell);

            doc.Add(headerTable);

            /*
            doc.Add(new Paragraph(String.Format("Plan ID = {0}. Courier (ID) = {1} ({2})\n",
                                                locations[0].PlanId,
                                                locations[0].Courier.Customer.Email,
                                                locations[0].CourierId),
                                  titleFont));

            doc.Add(new Paragraph(" ", titleFont));
            doc.Add(new Paragraph(String.Format("Driver Signature: {0}  Manager Signature: {1}\n",
                                                "___________________", "___________________"), titleFont));
            doc.Add(new Paragraph(" ", titleFont));
            */

            int locNumber = 1;
            int numberOfTableColumns = 10;
            var displayQrCode = false;
            if (_qrCodeSettings.Enabled && trackingUrls != null &&
                trackingUrls.Count == locations.Count)
            {
                numberOfTableColumns++;
                displayQrCode = true;
            }

            var table = new PdfPTable(numberOfTableColumns);
            table.HorizontalAlignment = Element.ALIGN_LEFT;
            table.WidthPercentage = 100f;
            if (numberOfTableColumns == 10)
            {
                table.SetWidths(new int[] { 5, 20, 10, 6, 5, 8, 5, 6, 13, 15 });
            }
            else // numberOfTableColumns == 11 including QR code.
            {
                table.SetWidths(new int[] { 5, 20, 10, 6, 9, 5, 9, 5, 6, 12, 13 });
            }

            // this allows repeating table's header row on each printed page.
            table.HeaderRows = 1;

            var titleCell = new PdfPCell(new Phrase("Stop", columnTitleFont));
            titleCell.Border = Rectangle.BOTTOM_BORDER;
            titleCell.HorizontalAlignment = Element.ALIGN_CENTER;
            table.AddCell(titleCell);

            titleCell.Phrase = new Phrase("Address", columnTitleFont);
            table.AddCell(titleCell);

            titleCell.Phrase = new Phrase("Measurement", columnTitleFont);
            table.AddCell(titleCell);

            titleCell.Phrase = new Phrase("PackageID", columnTitleFont);
            table.AddCell(titleCell);

            if (displayQrCode)
            {
                titleCell.Phrase = new Phrase("QRCode", columnTitleFont);
                table.AddCell(titleCell);
            }

            titleCell.Phrase = new Phrase("Tracking#", columnTitleFont);
            table.AddCell(titleCell);

            titleCell.Phrase = new Phrase("Action", columnTitleFont);
            table.AddCell(titleCell);

            titleCell.Phrase = new Phrase("Time", columnTitleFont);
            table.AddCell(titleCell);

            titleCell.Phrase = new Phrase("Updated", columnTitleFont);
            table.AddCell(titleCell);

            titleCell.Phrase = new Phrase("Signature", columnTitleFont);
            table.AddCell(titleCell);

            titleCell.Phrase = new Phrase("Reference", columnTitleFont);
            table.AddCell(titleCell);

            var baseWeight = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId);
            var baseWeightIn = baseWeight != null ? baseWeight.Name : "";
            var baseDimension = _measureService.GetMeasureDimensionById(_measureSettings.BaseDimensionId);
            var baseDimensionIn = baseDimension != null ? baseDimension.Name : "";

            foreach (var loc in locations)
            {
                var locActionPickup = loc.Id == loc.Package.PickUpLocationId;

                var cell = new PdfPCell(new Phrase(locNumber.ToString("0000"), font));
                cell.Border = Rectangle.BOTTOM_BORDER;
                cell.HorizontalAlignment = Element.ALIGN_LEFT;
                cell.PaddingTop = 8.0f;
                cell.PaddingBottom = 8.0f;
                table.AddCell(cell);

                sb.Clear();
                sb.Append(String.Format("{0}\n", loc.Address.FormattedAddress()));
                if (!String.IsNullOrWhiteSpace(loc.Address.Company))
                {
                    sb.Append(String.Format("{0}\n", loc.Address.Company));
                }
                sb.Append(String.Format("{0} {1}\nCell: {2} ; 2nd: {3}\n", loc.Address.FirstName, loc.Address.LastName,
                                        loc.Address.CellPhoneNumber, loc.Address.PhoneNumber));

                var addressDisplayInfo = sb.ToString();

                cell.Phrase = new Phrase(addressDisplayInfo, font);
                table.AddCell(cell);

                string pkgMeasure = "";
                pkgMeasure += loc.Package.Shipment.Length.HasValue && loc.Package.Shipment.Width.HasValue && loc.Package.Shipment.Height.HasValue ?
                    string.Format("{1:F2} x {2:F2} x {3:F2} {0}", baseDimensionIn, loc.Package.Shipment.Length.Value, loc.Package.Shipment.Width.Value, loc.Package.Shipment.Height.Value) : "";
                pkgMeasure += loc.Package.Shipment.TotalWeight.HasValue ? string.Format("\n{0:F3} {1}", loc.Package.Shipment.TotalWeight.Value, baseWeightIn) : "";

                cell.Phrase = new Phrase(pkgMeasure, font);
                table.AddCell(cell);

                cell.Phrase = new Phrase(loc.PackageId.ToString(), font);
                table.AddCell(cell);

                /* Decided to use display the QRcode differently (i.e. re-genrate everytime!)
                 * 
                // Try to see if the QR Code picture file exists (i.e. already pre-generated prior to trying to PDF it).
                // If not, then just enter space rather than the actual QR Code picture.
                var picBinary = _pictureService.LoadLogisticsPackageQrCodePictureFromFile(loc.PackageId.Value, "image/jpeg");
                if (picBinary != null && picBinary.Length > 0)
                {
                    var pictureLocalPath = _pictureService.GetPackageQrCodePictureLocalPath(loc.PackageId.Value, 100, false);
                    cell = new PdfPCell(Image.GetInstance(pictureLocalPath));
                }
                else
                {
                    cell = new PdfPCell(new Phrase(" ", font));
                }
                cell.HorizontalAlignment = Element.ALIGN_LEFT;
                cell.Border = Rectangle.NO_BORDER;
                table.AddCell(cell);
                */

                if (displayQrCode)
                {
                    var trackingUrl = trackingUrls[locNumber - 1];
                    if (!String.IsNullOrEmpty(trackingUrl))
                    {
                        Image trackingQrCodeImg = new BarcodeQRCode(trackingUrl, 20, 20, null).GetImage();
                        var cellQr = new PdfPCell(trackingQrCodeImg);
                        cellQr.Border = Rectangle.BOTTOM_BORDER;
                        cellQr.HorizontalAlignment = Element.ALIGN_CENTER;
                        cellQr.VerticalAlignment = Element.ALIGN_MIDDLE;
                        cellQr.PaddingTop = cell.PaddingTop;
                        cellQr.PaddingBottom = cell.PaddingBottom;
                        table.AddCell(cellQr);
                    }
                    else
                    {
                        cell.Phrase = new Phrase(" ", font);
                        table.AddCell(cell);
                    }
                }

                cell.Phrase = new Phrase(loc.Package.Shipment.TrackingNumber, font);
                table.AddCell(cell);

                var locAction = locActionPickup ? "Pick Up" : "Delivery";

                cell.Phrase = new Phrase(locAction, font);
                cell.HorizontalAlignment = Element.ALIGN_CENTER;
                table.AddCell(cell);

                cell.HorizontalAlignment = Element.ALIGN_LEFT;

                if (locActionPickup && loc.Package.ReadyOnUtc.HasValue)
                {
                    var from = _dateTimeHelper.ConvertToUserTime(loc.Package.ReadyOnUtc.Value, DateTimeKind.Utc).ToShortTimeString();
                    var to = _dateTimeHelper.ConvertToUserTime(loc.Package.PickupEndOnUtc.Value, DateTimeKind.Utc).ToShortTimeString();

                    cell.Phrase = new Phrase(String.Format("{0}-{1}", from, to), font);
                    table.AddCell(cell);
                }
                else
                {
                    cell.Phrase = new Phrase("N/A", font);
                    table.AddCell(cell);
                }

                cell.Phrase = new Phrase(_dateTimeHelper.ConvertToUserTime(loc.UpdatedOnUtc.Value, DateTimeKind.Utc).ToString(), font);
                table.AddCell(cell);

                cell.Phrase = new Phrase("");
                table.AddCell(cell);

                // TODO: Update to pull additional comments from database or object
                var comment = loc.Package.Shipment.Comment;
                cell.Phrase = new Phrase(comment ?? "", font);
                table.AddCell(cell);

                locNumber++;
            }

            doc.Add(table);
            doc.Close();
        }

        /// <summary>
        /// Print logistics waybill to PDF
        /// </summary>
        /// <param name="stream">Stream</param>
        /// <param name="package">Logistics package</param>
        /// <param name="trackingUrl">Package tracking url string</param>
        /// <param name="lang">Language</param>
        public virtual void PrintLogisticsWaybillToPdf(Stream stream, LogisticsPackage package, string trackingUrl, Language lang)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            if (package == null)
                throw new ArgumentNullException("package");

            if (String.IsNullOrEmpty(trackingUrl))
                throw new ArgumentNullException("trackingUrl");

            if (lang == null)
                throw new ArgumentNullException("lang");

            PrintLogisticsWaybillToPdfPriv(stream, package, trackingUrl, lang);
        }

        /// <summary>
        /// Print logistics waybill to PDF
        /// </summary>
        /// <param name="stream">Stream</param>
        /// <param name="package">Logistics package</param>
        /// <param name="trackingUrl">Package tracking url string</param>
        /// <param name="lang">Language</param>
        /// <param name="isisReturnRequestLogisticOrder">add return to shipping lable</param>
        public virtual void PrintLogisticsWayBillToPdfWithReturn(Stream stream, LogisticsPackage package, string trackingUrl, Language lang, bool isisReturnRequestLogisticOrder)
        {

            if (stream == null)
                throw new ArgumentNullException("stream");

            if (package == null)
                throw new ArgumentNullException("package");

            if (String.IsNullOrEmpty(trackingUrl))
                throw new ArgumentNullException("trackingUrl");

            if (lang == null)
                throw new ArgumentNullException("lang");

            PrintLogisticsWaybillToPdfPriv(stream, package, trackingUrl, lang, isisReturnRequestLogisticOrder);
        }

        private void PrintLogisticsWaybillToPdfPriv(Stream stream, LogisticsPackage package, string trackingUrl, Language lang, bool isisReturnRequestLogisticOrder = false)
        {
            checkPackageForWaybill(package);

            // define label page size
            var pixelsPerInch = PIXELS_PER_INCH;
            var widthInInch = WAYBILL_PAGE_WIDTH_IN_INCHES;
            var heightInInch = WAYBILL_PAGE_HEIGHT_IN_INCHES;
            var pageMarginInInch = 0.2f;
            var pageSize = new Rectangle(widthInInch * pixelsPerInch, heightInInch * pixelsPerInch);
            var pageMarginSize = pageMarginInInch * pixelsPerInch;

            var doc = new Document(pageSize, pageMarginSize, pageMarginSize, pageMarginSize, pageMarginSize);
            PdfWriter writer = PdfWriter.GetInstance(doc, stream);
            doc.Open();

            populateWaybillAsPdf(doc, package, trackingUrl, lang, isisReturnRequestLogisticOrder);

            printWayBillBorder(writer, doc);

            doc.Close();
        }

        /// <summary>
        /// Print logistics waybills for a list of packages to one PDF
        /// </summary>
        /// <param name="stream">Stream</param>
        /// <param name="packages">List of Logistics packages</param>
        /// <param name="trackingUrls">List of Packages' tracking url strings</param>
        /// <param name="lang">Language</param>
        public virtual void PrintLogisticsWaybillToPdf(Stream stream, IList<LogisticsPackage> packages, IList<string> trackingUrls, Language lang)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            if (packages == null)
                throw new ArgumentNullException("packages");

            if (trackingUrls == null)
                throw new ArgumentNullException("trackingUrls");

            if (lang == null)
                throw new ArgumentNullException("lang");

            if (packages.Count == 0)
                throw new ArgumentException("Parameter packages must be a list of at least one element");

            if (trackingUrls.Count == 0)
                throw new ArgumentException("Parameter trackingUrls must be a list of at least one element");

            if (trackingUrls.Count != packages.Count)
                throw new ArgumentException("Parameter trackingUrls must be a list of same size as parameter packages");

            // define label page size
            var pixelsPerInch = PIXELS_PER_INCH;
            var widthInInch = WAYBILL_PAGE_WIDTH_IN_INCHES;
            var heightInInch = WAYBILL_PAGE_HEIGHT_IN_INCHES;
            var pageMarginInInch = 0.2f;
            var pageSize = new Rectangle(widthInInch * pixelsPerInch, heightInInch * pixelsPerInch);
            var pageMarginSize = pageMarginInInch * pixelsPerInch;

            var doc = new Document(pageSize, pageMarginSize, pageMarginSize, pageMarginSize, pageMarginSize);
            PdfWriter writer = PdfWriter.GetInstance(doc, stream);
            doc.Open();

            populateWaybillAsPdf(doc, packages[0], trackingUrls[0], lang);

            for (int idx = 1; idx < packages.Count; idx++)
            {
                var package = packages[idx];
                var trackingUrl = trackingUrls[idx];

                checkPackageForWaybill(package);

                doc.NewPage();
                populateWaybillAsPdf(doc, package, trackingUrl, lang);

            }
            printWayBillBorder(writer, doc);

            doc.Close();
        }

        /// <summary>
        /// print picking
        /// </summary>
        /// <param name="stream">stream</param>
        /// <param name="variants">product variants</param>
        /// <param name="lang">language</param>
        /// <param name="orderId">orderid</param>
        public virtual void PrintPickingToPdf(Stream stream, List<PdfPackagePickingInfo> variants, Language lang, int orderId)
        {
            if (stream == null) throw new ArgumentNullException("stream");

            if (variants == null) throw new ArgumentNullException("variants");

            if (variants.Count <= 0)
                throw new ArgumentException("product varians must be a list of at least one element");

            PdfWriter pdfWriter = null;
            var doc = CreateDocument(stream, ref pdfWriter);

            try
            {
                //fonts
                var titleFont = GetFont();
                titleFont.SetStyle(Font.BOLD);
                titleFont.Color = BaseColor.BLACK;
                titleFont.Size = 7.2f;

                //fist table
                var headFont = GetFont();
                headFont.SetStyle(Font.BOLD);
                headFont.Color = BaseColor.BLACK;
                headFont.Size = 4f;

                var headValueFont = GetFont();
                headValueFont.Color = BaseColor.BLACK;
                headValueFont.Size = 4f;

                var footFont = GetFont();
                footFont.Size = 3f;
                footFont.SetStyle(Font.BOLD);

                // create head title
                var titleTable = new PdfPTable(1) { WidthPercentage = 100f };

                titleTable.AddCell(new PdfPCell
                {
                    Border = Rectangle.NO_BORDER,
                    HorizontalAlignment = Element.ALIGN_RIGHT,
                    Phrase = new Phrase("SpotsHUB Online Order", titleFont)
                });


                titleTable.AddCell(new PdfPCell
                {
                    Border = Rectangle.NO_BORDER,
                    HorizontalAlignment = Element.ALIGN_RIGHT,
                    Phrase = new Phrase("Picking List", titleFont)
                });

                doc.Add(titleTable);

                BuildPickingHeadTable(doc, headFont, headValueFont, orderId);

                // up space 
                AddSpace(doc, 1);

                BuildPickingMiddleContentTable(doc, headFont, headValueFont, variants);

                AddSpace(doc, 2);

                BuildPickingFootContentTable(doc, headValueFont);

                AddSpace(doc, 2);

                var footP =
                    new Paragraph(
                        "Please retain this record and sumbit to warehouse manager once drop off to SHIPPING SORTING AREA.",
                        footFont) { Alignment = Element.ALIGN_CENTER };

                doc.Add(footP);
            }
            finally
            {
                doc.Close();
            }

        }

        private void BuildPickingHeadTable(Document doc, Font headFont, Font headValueFont, int orderId)
        {
            var headTable = new PdfPTable(3) { WidthPercentage = 60f, HorizontalAlignment = Element.ALIGN_LEFT };

            headTable.AddCell(new PdfPCell
            {
                HorizontalAlignment = Element.ALIGN_RIGHT,
                Phrase = new Phrase("Picking List No :", headFont)
            });

            headTable.AddCell(new PdfPCell
            {
                HorizontalAlignment = Element.ALIGN_LEFT,
                Colspan = 2,
                Phrase = new Phrase("", headValueFont)
            });

            headTable.AddCell(new PdfPCell
            {
                HorizontalAlignment = Element.ALIGN_RIGHT,
                Phrase = new Phrase("Date :", headFont)
            });

            headTable.AddCell(new PdfPCell
            {
                HorizontalAlignment = Element.ALIGN_LEFT,
                Colspan = 2,
                Phrase = new Phrase(DateTime.Now.ToString("MMM dd,yyyy", CultureInfo.CreateSpecificCulture("en-US")), headValueFont)
            });

            headTable.AddCell(new PdfPCell
            {
                HorizontalAlignment = Element.ALIGN_RIGHT,
                Phrase = new Phrase("Order Number :", headFont)
            });

            headTable.AddCell(new PdfPCell
            {
                HorizontalAlignment = Element.ALIGN_LEFT,
                Colspan = 2,
                Phrase = new Phrase(orderId.ToString(), headValueFont)
            });

            doc.Add(headTable);

            var contentTable = new PdfPTable(10);
            contentTable.HorizontalAlignment = Element.ALIGN_LEFT;
            contentTable.WidthPercentage = 100f;
        }

        private void AddSpace(Document doc, int num)
        {
            var spacingFont = GetFont();
            spacingFont.Size = 2f;

            var space = new Paragraph(String.Format(""), spacingFont)
            {
                SpacingAfter = 2f
            };
            for (int i = 0; i < num; i++)
            {
                doc.Add(space);
            }

        }

        private void BuildPickingMiddleContentTable(Document doc, Font headFont, Font headValueFont, List<PdfPackagePickingInfo> variants)
        {
            var contentTable = new PdfPTable(10);
            contentTable.WidthPercentage = 100f;

            contentTable.AddCell(new PdfPCell
            {
                HorizontalAlignment = Element.ALIGN_CENTER,
                Phrase = new Phrase("Location", headFont),
                Colspan = 2
            });
            contentTable.AddCell(new PdfPCell
            {
                HorizontalAlignment = Element.ALIGN_CENTER,
                Phrase = new Phrase("Product Description", headFont),
                Colspan = 4
            });
            contentTable.AddCell(new PdfPCell
            {
                HorizontalAlignment = Element.ALIGN_CENTER,
                Phrase = new Phrase("Item Number", headFont),
                Colspan = 2
            });
            contentTable.AddCell(new PdfPCell
            {
                HorizontalAlignment = Element.ALIGN_CENTER,
                Phrase = new Phrase("Quantity", headFont)
            });
            contentTable.AddCell(new PdfPCell
            {
                HorizontalAlignment = Element.ALIGN_CENTER,
                Phrase = new Phrase("Check", headFont)
            });

            foreach (var item in variants)
            {
                contentTable.AddCell(new PdfPCell
                {
                    HorizontalAlignment = Element.ALIGN_CENTER,
                    Colspan = 2,
                    Phrase = new Phrase(item.Variant.RackLocation, headValueFont)
                });
                contentTable.AddCell(new PdfPCell
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Colspan = 4,
                    Phrase = new Phrase(item.Variant.FullProductName, headValueFont)
                });
                contentTable.AddCell(new PdfPCell
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Colspan = 2,
                    Phrase = new Phrase(item.Variant.Gtin, headValueFont)
                });
                contentTable.AddCell(new PdfPCell
                {
                    HorizontalAlignment = Element.ALIGN_CENTER,
                    Phrase = new Phrase(item.Quantity.ToString(), headValueFont)
                });
                contentTable.AddCell(new PdfPCell
                {
                    HorizontalAlignment = Element.ALIGN_CENTER,
                    Phrase = new Phrase(string.Empty)
                });
            }

            doc.Add(contentTable);
        }

        private void BuildPickingFootContentTable(Document doc, Font headValueFont)
        {
            var footContentTable = new PdfPTable(5) { WidthPercentage = 100f, HorizontalAlignment = Element.ALIGN_RIGHT };

            footContentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 3,
                HorizontalAlignment = Element.ALIGN_RIGHT,
                Phrase = new Phrase("Order Picked By Staff ID :", headValueFont)
            });

            footContentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Colspan = 2,
                Phrase = new Phrase("_____________________________________________", headValueFont)
            });

            footContentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 3,
                HorizontalAlignment = Element.ALIGN_RIGHT,
                Phrase = new Phrase("Picker Signature :", headValueFont)
            });

            footContentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Colspan = 2,
                Phrase = new Phrase("_____________________________________________", headValueFont)
            });

            footContentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 3,
                HorizontalAlignment = Element.ALIGN_RIGHT,
                Phrase = new Phrase("Order Verified Sealed & Express order placed by Staff ID :", headValueFont)
            });

            footContentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Colspan = 2,
                Phrase = new Phrase("_____________________________________________", headValueFont)
            });

            footContentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 3,
                HorizontalAlignment = Element.ALIGN_RIGHT,
                Phrase = new Phrase("Verification Signature :", headValueFont)
            });

            footContentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Colspan = 2,
                Phrase = new Phrase("_____________________________________________", headValueFont)
            });

            footContentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 3,
                HorizontalAlignment = Element.ALIGN_RIGHT,
                Phrase = new Phrase("Scanned IN HUB & frop off to  Shipping Department by Staff ID :", headValueFont)
            });

            footContentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Colspan = 2,
                Phrase = new Phrase("_____________________________________________", headValueFont)
            });

            footContentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 3,
                HorizontalAlignment = Element.ALIGN_RIGHT,
                Phrase = new Phrase("Drop of to Courier sorting area Signature :", headValueFont)
            });

            footContentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Colspan = 2,
                Phrase = new Phrase("_____________________________________________", headValueFont)
            });

            doc.Add(footContentTable);
        }

        private Document CreateDocument(Stream stream, ref PdfWriter pdfWriter)
        {
            const float pixelsPerInch = PIXELS_PER_INCH;
            const float widthInInch = WAYBILL_PAGE_WIDTH_IN_INCHES;
            const float heightInInch = WAYBILL_PAGE_HEIGHT_IN_INCHES;
            const float pageMarginInInch = 0.2f;
            var pageSize = new Rectangle(widthInInch * pixelsPerInch, heightInInch * pixelsPerInch);
            const float pageMarginSize = pageMarginInInch * pixelsPerInch;

            var doc = new Document(pageSize, pageMarginSize, pageMarginSize, pageMarginSize, pageMarginSize);
            pdfWriter = PdfWriter.GetInstance(doc, stream);
            doc.Open();

            return doc;
        }

        public virtual void PrintMessageLabelToPdf(Stream stream, Dictionary<string, string> checkoutAttributes, Language language)
        {
            if (checkoutAttributes == null || checkoutAttributes.Count <= 0) return;

            if (stream == null) throw new ArgumentNullException("stream");

            if (checkoutAttributes == null) throw new ArgumentNullException("checkoutAttributes");

            if (checkoutAttributes.Count <= 0)
                throw new ArgumentException("message gift  must be a list of at least one element");

            PdfWriter pdfWriter = null;
            var doc = CreateDocument(stream, ref pdfWriter);

            try
            {
                BuildMessagGiftForPdf(doc, checkoutAttributes);

                printWayBillBorder(pdfWriter, doc);
            }
            finally
            {
                doc.Close();
            }

        }

        private void BuildMessagGiftForPdf(Document doc, Dictionary<string, string> checkoutAttributes)
        {
            var fontContent = GetRobotoFont();
            var fontBold = GetRobotoBoldFont();
            fontContent.Size = 8f;
            fontBold.Size = 8f;


            //head 
            BuildMessageGiftHeadForPDF(doc, fontBold, fontContent, checkoutAttributes.ContainsKey("receiver") ? checkoutAttributes["receiver"] : string.Empty);

            AddSpace(doc, 4);

            //body
            BuildMessageGiftBodyForPdf(doc, checkoutAttributes, fontBold, fontContent);
        }

        private void BuildMessageGiftHeadForPDF(Document doc, Font fontBold, Font fontContent, string receiver)
        {
            var headTable = new PdfPTable(5) { WidthPercentage = 100f };
            headTable.AddCell(
                new PdfPCell(Image.GetInstance(HostingEnvironment.MapPath("~/Content/images/logo_print.png")))
                {
                    Border = Rectangle.NO_BORDER,
                    HorizontalAlignment = Element.ALIGN_CENTER,
                    VerticalAlignment = Element.ALIGN_TOP,
                    Colspan = 5,
                    FixedHeight = 50f
                });
            doc.Add(headTable);
            doc.Add(Chunk.NEWLINE);
            doc.Add(Chunk.NEWLINE);
            doc.Add(Chunk.NEWLINE);
            doc.Add(Chunk.NEWLINE);
            doc.Add(Chunk.NEWLINE);

            headTable = new PdfPTable(12) { WidthPercentage = 100f };
            headTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 1
            });
            fontContent.Size = 10f;
            headTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                HorizontalAlignment = Element.ALIGN_LEFT,
                VerticalAlignment = Element.ALIGN_BOTTOM,
                Phrase = new Phrase { new Chunk("To: ", fontBold), new Chunk(receiver, fontContent) },
                Colspan = 10
            });
            headTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 1
            });

            doc.Add(headTable);
        }

        private void BuildMessageGiftBodyForPdf(Document doc, Dictionary<string, string> checkoutAttributes, Font fontBold, Font fontContent)
        {
            doc.Add(Chunk.NEWLINE);
            doc.Add(Chunk.NEWLINE);
            fontContent.Size = 9f;
            var contentTable = new PdfPTable(12) { WidthPercentage = 100f };
            var content =
                new Phrase(string.Format("{0}.", checkoutAttributes.ContainsKey("message") ? checkoutAttributes["message"] : string.Empty), fontContent);
            content.Leading = 18f;
            BaseColor contentBgColor = new BaseColor(196, 212, 237);
            contentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 1,
            });
            contentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                HorizontalAlignment = Element.ALIGN_LEFT,
                VerticalAlignment = Element.ALIGN_BOTTOM,
                Phrase = content,
                Colspan = 10,
            });
            contentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 1,
            });


            doc.Add(contentTable);
            AddSpace(doc, 7);
            doc.Add(Chunk.NEWLINE);
            doc.Add(Chunk.NEWLINE);
            doc.Add(Chunk.NEWLINE);
            contentTable = new PdfPTable(12) { WidthPercentage = 100f };
            string sender = string.Format("{0}.", checkoutAttributes.ContainsKey("sender") ? checkoutAttributes["sender"] : string.Empty, fontContent);
            contentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 1,
            });
            fontContent.Size = 9f;
            contentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                HorizontalAlignment = Element.ALIGN_LEFT,
                VerticalAlignment = Element.ALIGN_BOTTOM,
                Phrase = new Phrase { new Chunk("From: ", fontBold), new Chunk(sender, fontContent) },
                Colspan = 10
            });
            contentTable.AddCell(new PdfPCell
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 1,
            });
            doc.Add(contentTable);
        }

        #endregion


        #region

        public virtual void PrintPacking(Stream stream, PrintPackingModel packingPackingModel)
        {
            var pixelsPerInch = PIXELS_PER_INCH;
            var widthInInch = WAYBILL_PAGE_WIDTH_IN_INCHES;
            var heightInInch = WAYBILL_PAGE_HEIGHT_IN_INCHES;
            var pageMarginInInch = 0.2f;
            var pageSize = new Rectangle(widthInInch * pixelsPerInch, heightInInch * pixelsPerInch);
            var pageMarginSize = pageMarginInInch * pixelsPerInch;



            #region top table
            var table = new PdfPTable(12) { WidthPercentage = 100f };
            table.HorizontalAlignment = Element.ALIGN_LEFT;
            //font
            BaseFont bfTimes = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, false);
            Font font = new Font(bfTimes, 5, Font.NORMAL);
            Font font1 = new Font(bfTimes, 3, Font.NORMAL);
            Font font2 = new Font(bfTimes, 4, Font.NORMAL);
            var fontContent = GetRobotoFont();
            var fontBold = GetRobotoBoldFont();
            fontContent.Size = 5f;
            fontBold.Size = 5f;

            var cell = new PdfPCell();

            table.AddCell(
                new PdfPCell(Image.GetInstance(HostingEnvironment.MapPath("~/Content/images/logo_print.png")))
                {
                    Border = Rectangle.NO_BORDER,
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    VerticalAlignment = Element.ALIGN_TOP,
                    Colspan = 4,
                    FixedHeight = 30f
                });

            fontContent.Size = 6.5f;
            Paragraph tagParagraph = new Paragraph();
            tagParagraph.Add(new Phrase("We Deliver Happiness!", fontContent));
            tagParagraph.SetLeading(0, 1.3f);
            tagParagraph.Font = fontContent;
            tagParagraph.Alignment = Element.ALIGN_CENTER;
            cell = new PdfPCell()
            {
                Border = Rectangle.NO_BORDER,
                HorizontalAlignment = Element.ALIGN_CENTER,
                VerticalAlignment = Element.ALIGN_TOP,
                Colspan = 4
            };
            cell.AddElement(tagParagraph);
            table.AddCell(cell);

            fontContent.Size = 5f;
            Paragraph orderParagraph = new Paragraph();
            orderParagraph.Font = fontContent;
            orderParagraph.SetLeading(0, 1.3f);
            orderParagraph.Alignment = Element.ALIGN_RIGHT;
            orderParagraph.Add("Order: #" + packingPackingModel.OrderNumber + "\n");
            orderParagraph.Add("Date: " + packingPackingModel.OrderDate.ToShortDateString());
            cell = new PdfPCell()
            {
                Border = Rectangle.NO_BORDER,
                HorizontalAlignment = Element.ALIGN_RIGHT,
                VerticalAlignment = Element.ALIGN_TOP,
                Colspan = 4
            };
            cell.AddElement(orderParagraph);
            table.AddCell(cell);

            table.AddCell(new PdfPCell()
            {
                Colspan = 12,
                Border = Rectangle.NO_BORDER
            });

            Paragraph shippingParagraph = new Paragraph();
            shippingParagraph.Font = fontContent;
            shippingParagraph.SetLeading(0, 1.3f);

            shippingParagraph.Add(Chunk.NEWLINE);
            shippingParagraph.Add(new Phrase("Shipping Address" + "\n", fontBold));
            if (!String.IsNullOrEmpty(packingPackingModel.Company))
            {
                shippingParagraph.Add("Company: " + packingPackingModel.Company + "\n");
            }
            shippingParagraph.Add(packingPackingModel.FirstName + " " + packingPackingModel.LastName + "\n");
            if (!String.IsNullOrEmpty(packingPackingModel.Address2))
            {
                shippingParagraph.Add(packingPackingModel.Address2 + " ");
            }
            shippingParagraph.Add(packingPackingModel.Address1 + "\n");
            if (!String.IsNullOrEmpty(packingPackingModel.City))
            {
                shippingParagraph.Add(packingPackingModel.City + ", ");
            }
            if (!String.IsNullOrEmpty(packingPackingModel.StateProvince))
            {
                shippingParagraph.Add(packingPackingModel.StateProvince);
            }
            if (!String.IsNullOrEmpty(packingPackingModel.ZipPostalCode))
            {
                shippingParagraph.Add(" " + packingPackingModel.ZipPostalCode.ToUpper());
            }
            cell = new PdfPCell()
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 12
            };

            cell.AddElement(shippingParagraph);
            table.AddCell(cell);

            fontContent.Size = 4f;

            Paragraph paragraph = new Paragraph();
            paragraph.SetLeading(0, 1.3f);
            paragraph.Add(new Phrase("Shipped via: SpotsHUB EXPRESS Courier Service", fontContent));
            cell = new PdfPCell()
            {
                Border = Rectangle.NO_BORDER,
                Colspan = 12
            };
            cell.AddElement(paragraph);
            table.AddCell(cell);

            #endregion

            #region allTable
            var allTable = new PdfPTable(1) { WidthPercentage = 85f };

            var allTable_Cell = new PdfPCell();
            allTable_Cell.Border = Rectangle.NO_BORDER;
            allTable_Cell.AddElement(table);
            allTable_Cell.Padding = 0;
            allTable.AddCell(allTable_Cell);

            fontContent.Size = 5f;

            var allTable_Cell1 = new PdfPCell();
            allTable_Cell1.Border = Rectangle.NO_BORDER;

            var allTable_Cell1_table = new PdfPTable(12) { WidthPercentage = 100f };
            allTable_Cell1_table.SpacingBefore = 10f;
            allTable_Cell1_table.SpacingAfter = 20f;
            allTable_Cell1_table.HorizontalAlignment = Element.ALIGN_LEFT;

            fontBold.Size = 5f;
            allTable_Cell1_table.AddCell(
                new PdfPCell
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Phrase = new Phrase("Product", fontBold),
                    Colspan = 6
                });
            allTable_Cell1_table.AddCell(
                new PdfPCell
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Phrase = new Phrase("Item Number", fontBold),
                    Colspan = 3
                });
            allTable_Cell1_table.AddCell(
                new PdfPCell
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Phrase = new Phrase("Qantity", fontBold),
                    Colspan = 3
                });

            foreach (var item in packingPackingModel.ItemList)
            {
                paragraph = new Paragraph();
                paragraph.Add(new Phrase(item.Name, fontContent));
                if (!String.IsNullOrEmpty(item.Attributes))
                {
                    paragraph.Add("\n");
                    paragraph.Add(new Phrase(item.Attributes, fontContent));
                }
                allTable_Cell1_table.AddCell(
                new PdfPCell(paragraph)
                {
                    HorizontalAlignment = Element.ALIGN_LEFT,
                    Colspan = 6
                });
                allTable_Cell1_table.AddCell(
               new PdfPCell
               {
                   HorizontalAlignment = Element.ALIGN_LEFT,
                   Phrase = new Phrase(string.IsNullOrEmpty(item.Number) ? "" : item.Number, fontContent),
                   Colspan = 3
               });
                allTable_Cell1_table.AddCell(
               new PdfPCell
               {
                   HorizontalAlignment = Element.ALIGN_LEFT,
                   Phrase = new Phrase(item.Qantity.ToString(), fontContent),
                   Colspan = 3
               });
            }

            allTable.AddCell(allTable_Cell1);

            var allTable_Cell1_table_Cell = new PdfPCell();
            allTable_Cell1_table_Cell.Border = Rectangle.NO_BORDER;
            allTable_Cell1_table_Cell.AddElement(allTable_Cell1_table);
            allTable.AddCell(allTable_Cell1_table_Cell);

            #endregion

            #region bottom
            var explain = new StringBuilder();
            explain.AppendLine("Return policy:");
            explain.AppendLine("• SpotsHUB accept return for most products within 30 days of delivery.");
            explain.AppendLine("• Some products have different policies or requirements associated with them.");
            explain.AppendLine("• Food products are not returnable.");
            explain.AppendLine("• For health and hygiene reasons, some products cannot be return after delivery.");
            explain.AppendLine("• Full refund only applies to return products that meet one of the following conditions:");
            explain.AppendLine("- Return product must be brand new, and the packaging must never been opened and be in resalable condition.");
            explain.AppendLine("- Product is returned due to a SpotsHUB error (e.g., wrong product was sent). SpotsHUB will cover the full return shipping costs.");
            explain.AppendLine("- Product received is damaged or defective. Refund will be issued once the return request is approved by SpotsHUB.");
            explain.AppendLine("• Final sale products are not eligible for return or exchange.");
            explain.AppendLine("• A 40% restocking fee will apply to return products with one of the following return reasons and buyers will be responsible for the full return shipping costs:");
            explain.AppendLine("- Buyers have changed their mind about a purchase and return the product in its original condition within the allowable return window.");
            explain.AppendLine("- Buyers have returned a product in its original condition but passed the deadline of return for more than 15 days. Buyers are given the 15 days from the deadline to return the product to SpotsHUB.");
            explain.AppendLine("- Buyers have refused to accept the delivery of the product. ");
            explain.AppendLine("- Buyers have returned a product with missing parts, not in its original condition, with obvious signs of usage, and because of any other reasons that is not due to a SpostHUB error.");
            explain.AppendLine("• No return and refund will be approved for products damaged due to faulty usage or installation by buyers.");
            explain.AppendLine("• Return and refund requests may only be initiated from the original accounts of order placement.");
            explain.Append("\n\n");
            explain.Append("SpotsHUB Customer Service Team" + "\n");
            explain.Append("Phone: 604-290-9888" + "\n");
            explain.Append("Email: info@spotshub.com" + "\n");
            fontContent.Size = 4f;
            var allTable_Cell_topCell = new PdfPCell();
            allTable_Cell_topCell.Border = Rectangle.NO_BORDER;
            allTable_Cell_topCell.AddElement(new Paragraph(explain.ToString(), fontContent));
            allTable.AddCell(allTable_Cell_topCell);
            #endregion

            var doc = new Document(pageSize, pageMarginSize, pageMarginSize, pageMarginSize, pageMarginSize);
            var writer = PdfWriter.GetInstance(doc, stream);
            doc.Open();
            doc.Add(allTable);
            doc.Close();
        }

        #endregion
    }
}